Compare commits

...

38 Commits

Author SHA1 Message Date
github-actions[bot]
5498456fa8 Bump version to 2.10.20 on release-2.10 branch (#24468)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: alexmt <426437+alexmt@users.noreply.github.com>
2025-09-08 13:15:08 -07:00
Alexander Matyushentsev
7bd0c3669f chore(deps): bump slsa-framework/slsa-github-generator from 2.0.0 to 2.1.0 (#23166) (#24467)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 13:10:10 -07:00
github-actions[bot]
c9a7c0cd47 Bump version to 2.10.19 on release-2.10 branch (#24464)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: alexmt <426437+alexmt@users.noreply.github.com>
2025-09-08 11:52:18 -07:00
Alexander Matyushentsev
a80f192b4f fix(security): repository.GetDetailedProject exposes repo secrets (#24387) (#24462)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-08 11:44:54 -07:00
github-actions[bot]
3d900c7084 Bump version to 2.10.18 (#20435)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: crenshaw-dev <crenshaw-dev@users.noreply.github.com>
2024-10-17 16:10:20 -04:00
nmirasch
a3e235907a fix: CVE-2024-43799 upgrading transitive dep express to 4.21.0 (#20400) 2024-10-16 07:52:23 -04:00
github-actions[bot]
6e33cba80e Bump version to 2.10.17 (#20117)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: ishitasequeira <ishitasequeira@users.noreply.github.com>
2024-09-26 02:29:03 -04:00
gcp-cherry-pick-bot[bot]
1200b6c42d chore(deps): bump dompurify from 2.3.6 to 2.5.6 in /ui (#19955) (#20031)
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 2.3.6 to 2.5.6.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/2.3.6...2.5.6)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-25 08:14:40 -04:00
gcp-cherry-pick-bot[bot]
f52dcf6f3c fix: CVE-2024-45296 Backtracking regular expressions cause ReDoS by upgrading path-to-regexp from 1.8.0 to 1.9.0 (#20087) (#20092)
Signed-off-by: Cheng Fang <cfang@redhat.com>
Co-authored-by: Cheng Fang <cfang@redhat.com>
2024-09-25 00:13:22 -04:00
Ishita Sequeira
6b0060587d chore(deps-dev): bump webpack from 5.84.1 to 5.94.0 in /ui (#20054)
* cherry-pick chore(deps-dev): bump webpack from 5.84.1 to 5.94.0 in /ui

Signed-off-by: Ishita Sequeira <ishiseq29@gmail.com>

* fix yarn

Signed-off-by: Ishita Sequeira <ishiseq29@gmail.com>

---------

Signed-off-by: Ishita Sequeira <ishiseq29@gmail.com>
2024-09-23 09:55:52 -04:00
Cheng Fang
9865a8a340 chore(deps): bump express from 4.19.2 to 4.20.0 in /ui (#19883) (#19990) 2024-09-18 17:21:45 -04:00
gcp-cherry-pick-bot[bot]
b3c2bc114b chore(deps): bump express from 4.17.3 to 4.19.2 in /ui (#17648) (#19266)
Bumps [express](https://github.com/expressjs/express) from 4.17.3 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.3...4.19.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Keith Chong <kykchong@redhat.com>
2024-09-04 20:14:51 -04:00
Alexander Matyushentsev
286568e73a fix: diffing should not fail if resource fail schema validation (#19734)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-08-29 16:56:13 -04:00
Jae Ryong Song
5b041c2af2 fix: docs version regex changed (#18756) (#19355)
Signed-off-by: jasong <jasong@student.42seoul.kr>
2024-08-04 13:14:11 -07:00
Alexander Matyushentsev
a1d375836e fix: ArgoCD 2.11 - Loop of PATCH calls to Application objects (#19340) (#19348)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-08-04 12:50:06 -07:00
Mangaal
c02a3d775c upgrade github.com/hashicorp/go-retryablehttp to v0.7.7 (#19237)
Signed-off-by: Mangaal <angommeeteimangaal@gmail.com>
2024-07-25 20:52:01 -04:00
github-actions[bot]
3bf801f2df Bump version to 2.10.16 (#19177)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <39732895+pasha-codefresh@users.noreply.github.com>
2024-07-24 12:32:14 +03:00
pasha-codefresh
ef535230d8 Merge commit from fork
* feat: verify rbac on each message and not just during handshake

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: verify rbac on each message and not just during handshake

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix: linter and e2e tests

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix: linter and e2e tests

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* feat: verify rbac on each message and not just during handshake

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-07-24 12:18:15 +03:00
github-actions[bot]
14963d7fac Bump version to 2.10.15 (#19143)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <39732895+pasha-codefresh@users.noreply.github.com>
2024-07-22 17:19:41 +03:00
pasha-codefresh
46c0c0b64d Merge commit from fork
* feat: limit payload size

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix cherry-pick issues

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix cherry-pick issues

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix cherry-pick issues

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix cherry-pick issues

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix cherry-pick issues

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix lint and test issues

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-07-22 17:08:18 +03:00
github-actions[bot]
794b2e050d Bump version to 2.10.14 (#19062)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: crenshaw-dev <crenshaw-dev@users.noreply.github.com>
2024-07-15 13:35:23 -04:00
Andy Goldstein
d8ddce87be chore: update gitops-engine (#19054)
This update includes critical fixes that resolve an issue where
cluster-scoped resources could have been accidentally deleted during an
application sync if pruning is enabled.

Signed-off-by: Andy Goldstein <andy.goldstein@gmail.com>
2024-07-15 11:17:03 -04:00
gcp-cherry-pick-bot[bot]
7e99a1340e fix(cli): Get Redis password from secret in loadClusters() (#18951) (#18957)
* Get Redis password from secret in `loadClusters()`



* feat: support redis password in admin stats command



* Simplify code



---------

Signed-off-by: David Wu <155603967+david-wu-octopus@users.noreply.github.com>
Signed-off-by: pashakostohrys <pavel@codefresh.io>
Co-authored-by: david-wu-octopus <155603967+david-wu-octopus@users.noreply.github.com>
Co-authored-by: pashakostohrys <pavel@codefresh.io>
2024-07-05 11:12:49 -04:00
github-actions[bot]
63a30293fe Bump version to 2.10.13 (#18895)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: crenshaw-dev <crenshaw-dev@users.noreply.github.com>
2024-07-02 13:39:12 -04:00
Michael Crenshaw
2fbb69b892 fix: update static schemas (#18890)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-07-02 12:51:07 -04:00
Michael Crenshaw
9c711337e7 fix(controller): bad server-side diffs (#18213) (2.10) (#18869)
* fix(controller): bad server-side diffs (#18213) (2.10)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

* fix revision

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

* hopefully the right hash now

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-07-01 14:32:24 -04:00
gcp-cherry-pick-bot[bot]
2c2064be7b docs: Fix .path to .path.segments go template (#18872) (#18875)
Signed-off-by: Jaeseok Lee <devsunb@gmail.com>
Co-authored-by: Jaeseok Lee <devsunb@gmail.com>
2024-07-01 10:54:18 -04:00
gcp-cherry-pick-bot[bot]
9d8148bc61 fix: Update braces package to 3.0.3 (#18459) (#18664)
Signed-off-by: Keith Chong <kykchong@redhat.com>
Co-authored-by: Keith Chong <kykchong@redhat.com>
2024-06-14 09:18:30 -04:00
gcp-cherry-pick-bot[bot]
9ba6943111 test: fix e2e tests after GHSA-3cqf-953p-h5cp (#18543) (#18553)
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-06-07 11:50:21 -04:00
Justin Marquis
c79714d660 chore: bump go version to 1.21.10 (#18541)
Signed-off-by: Justin Marquis <justin@akuity.io>
2024-06-07 08:49:20 -07:00
github-actions[bot]
cb6f5ac8b8 Bump version to 2.10.12 (#18521)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <39732895+pasha-codefresh@users.noreply.github.com>
2024-06-06 11:44:25 +03:00
pasha-codefresh
ec35043a64 Merge pull request from GHSA-3cqf-953p-h5cp
* fix: prevent enumerating by cluster name, return exact error for case when cluster exists and not

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix: prevent cluster enumeration by name

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix: prevent cluster enumeration by name

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter and add unit test

Signed-off-by: pashakostohrys <pavel@codefresh.io>

* fix linter and add unit test

Signed-off-by: pashakostohrys <pavel@codefresh.io>

---------

Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-06-06 11:30:10 +03:00
Blake Pettersson
531123b70c Merge pull request from GHSA-87p9-x75h-p4j2
Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
2024-06-06 11:25:55 +03:00
github-actions[bot]
27e49f8b78 Bump version to 2.10.11 (#18385)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: pasha-codefresh <39732895+pasha-codefresh@users.noreply.github.com>
2024-05-23 16:33:02 +03:00
pasha-codefresh
82ae349929 fix: remove Egress NetworkPolicy for argocd-redis and argocd-redis-ha-haproxy - 2.10 (#18381)
Signed-off-by: pashakostohrys <pavel@codefresh.io>
2024-05-23 16:03:33 +03:00
Michael Crenshaw
f61f47264f fix: revert registry change (#18328) (#18336)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-05-21 17:37:42 -04:00
gcp-cherry-pick-bot[bot]
0a179fb98e fix(deps): upgrade otel dependency (#18285) (#18325)
Signed-off-by: Justin Marquis <justin@akuity.io>
Co-authored-by: Justin Marquis <76892343+34fathombelow@users.noreply.github.com>
Co-authored-by: Soumya Ghosh Dastidar <44349253+gdsoumya@users.noreply.github.com>
2024-05-21 10:47:58 -07:00
gcp-cherry-pick-bot[bot]
a960c6be07 chore(ci): fix release notes (#18132) (#18331)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-05-21 12:53:25 -04:00
55 changed files with 1397 additions and 560 deletions

View File

@@ -52,7 +52,7 @@ jobs:
with:
go-version: ${{ env.GOLANG_VERSION }}
- name: Restore go build cache
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -117,7 +117,7 @@ jobs:
run: |
echo "/usr/local/bin" >> $GITHUB_PATH
- name: Restore go build cache
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -184,7 +184,7 @@ jobs:
run: |
echo "/usr/local/bin" >> $GITHUB_PATH
- name: Restore go build cache
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
@@ -270,7 +270,7 @@ jobs:
node-version: '20.7.0'
- name: Restore node dependency cache
id: cache-dependencies
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ui/node_modules
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -305,7 +305,7 @@ jobs:
fetch-depth: 0
- name: Restore node dependency cache
id: cache-dependencies
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ui/node_modules
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
@@ -401,7 +401,7 @@ jobs:
sudo chmod go-r $HOME/.kube/config
kubectl version
- name: Restore go build cache
uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ~/.cache/go-build
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}

View File

@@ -86,7 +86,7 @@ jobs:
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
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with:
image: ghcr.io/argoproj/argo-cd/argocd
digest: ${{ needs.build-and-publish.outputs.image-digest }}

View File

@@ -31,20 +31,20 @@ jobs:
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 }}
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@v2.1.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:
@@ -128,7 +128,7 @@ jobs:
contents: write # Needed for release uploads
if: github.repository == 'argoproj/argo-cd'
# Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.10.0
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
with:
base64-subjects: "${{ needs.goreleaser.outputs.hashes }}"
provenance-name: "argocd-cli.intoto.jsonl"
@@ -211,8 +211,8 @@ jobs:
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
# Must be referenced 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@v2.1.0
with:
base64-subjects: "${{ needs.generate-sbom.outputs.hashes }}"
provenance-name: "argocd-sbom.intoto.jsonl"

View File

@@ -114,7 +114,7 @@ changelog:
exclude:
- '^test:'
- '^.*?Bump(\([[:word:]]+\))?.+$'
- '^.*?[Bot](\([[:word:]]+\))?.+$'
- '^.*?\[Bot\](\([[:word:]]+\))?.+$'
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json

View File

@@ -4,7 +4,7 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:22.04@sha256:0bced47fffa3361afa981854fca
# 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.21.3@sha256:02d7116222536a5cf0fcf631f90b507758b669648e0f20186d2dc94a9b419a9b AS builder
FROM docker.io/library/golang:1.21.10@sha256:16438a8e66c0c984f732e815ee5b7d715b8e33e81bac6d6a3750b1067744e7ca AS builder
RUN echo 'deb http://archive.debian.org/debian buster-backports main' >> /etc/apt/sources.list
@@ -101,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.21.3@sha256:02d7116222536a5cf0fcf631f90b507758b669648e0f20186d2dc94a9b419a9b AS argocd-build
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.21.10@sha256:16438a8e66c0c984f732e815ee5b7d715b8e33e81bac6d6a3750b1067744e7ca AS argocd-build
WORKDIR /go/src/github.com/argoproj/argo-cd

View File

@@ -1 +1 @@
2.10.10
2.10.20

View File

@@ -101,7 +101,17 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie
if err != nil {
return nil, err
}
client := redis.NewClient(&redis.Options{Addr: fmt.Sprintf("localhost:%d", port)})
redisOptions := &redis.Options{Addr: fmt.Sprintf("localhost:%d", port)}
secret, err := kubeClient.CoreV1().Secrets(namespace).Get(context.Background(), defaulRedisInitialPasswordSecretName, v1.GetOptions{})
if err == nil {
if _, ok := secret.Data[defaultResisInitialPasswordKey]; ok {
redisOptions.Password = string(secret.Data[defaultResisInitialPasswordKey])
}
}
client := redis.NewClient(redisOptions)
compressionType, err := cacheutil.CompressionTypeFromString(redisCompressionStr)
if err != nil {
return nil, err

View File

@@ -46,13 +46,13 @@ func NewServer(initConstants plugin.CMPServerInitConstants) (*ArgoCDCMPServer, e
serverLog := log.NewEntry(log.StandardLogger())
streamInterceptors := []grpc.StreamServerInterceptor{
otelgrpc.StreamServerInterceptor(),
otelgrpc.StreamServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
grpc_logrus.StreamServerInterceptor(serverLog),
grpc_prometheus.StreamServerInterceptor,
grpc_util.PanicLoggerStreamServerInterceptor(serverLog),
}
unaryInterceptors := []grpc.UnaryServerInterceptor{
otelgrpc.UnaryServerInterceptor(),
otelgrpc.UnaryServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
grpc_logrus.UnaryServerInterceptor(serverLog),
grpc_prometheus.UnaryServerInterceptor,
grpc_util.PanicLoggerUnaryServerInterceptor(serverLog),

View File

@@ -1758,6 +1758,22 @@ func (ctrl *ApplicationController) normalizeApplication(orig, app *appv1.Applica
}
}
func createMergePatch(orig, new interface{}) ([]byte, bool, error) {
origBytes, err := json.Marshal(orig)
if err != nil {
return nil, false, err
}
newBytes, err := json.Marshal(new)
if err != nil {
return nil, false, err
}
patch, err := jsonpatch.CreateMergePatch(origBytes, newBytes)
if err != nil {
return nil, false, err
}
return patch, string(patch) != "{}", nil
}
// 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) (patchMs time.Duration) {
logCtx := log.WithFields(log.Fields{"application": orig.QualifiedName()})
@@ -1777,9 +1793,9 @@ func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, new
}
delete(newAnnotations, appv1.AnnotationKeyRefresh)
}
patch, modified, err := diff.CreateTwoWayMergePatch(
patch, modified, err := createMergePatch(
&appv1.Application{ObjectMeta: metav1.ObjectMeta{Annotations: orig.GetAnnotations()}, Status: orig.Status},
&appv1.Application{ObjectMeta: metav1.ObjectMeta{Annotations: newAnnotations}, Status: *newStatus}, appv1.Application{})
&appv1.Application{ObjectMeta: metav1.ObjectMeta{Annotations: newAnnotations}, Status: *newStatus})
if err != nil {
logCtx.Errorf("Error constructing app status patch: %v", err)
return

View File

@@ -986,7 +986,7 @@ func TestNormalizeApplication(t *testing.T) {
normalized := false
fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
if patchAction, ok := action.(kubetesting.PatchAction); ok {
if string(patchAction.GetPatch()) == `{"spec":{"project":"default"},"status":{"sync":{"comparedTo":{"destination":{},"source":{"repoURL":""}}}}}` {
if string(patchAction.GetPatch()) == `{"spec":{"project":"default"}}` {
normalized = true
}
}
@@ -1911,3 +1911,65 @@ func TestAddControllerNamespace(t *testing.T) {
assert.Equal(t, test.FakeArgoCDNamespace, updatedApp.Status.ControllerNamespace)
})
}
func TestHelmValuesObjectHasReplaceStrategy(t *testing.T) {
app := v1alpha1.Application{
Status: v1alpha1.ApplicationStatus{Sync: v1alpha1.SyncStatus{ComparedTo: v1alpha1.ComparedTo{
Source: v1alpha1.ApplicationSource{
Helm: &v1alpha1.ApplicationSourceHelm{
ValuesObject: &runtime.RawExtension{
Object: &unstructured.Unstructured{Object: map[string]interface{}{"key": []string{"value"}}},
},
},
},
}}},
}
appModified := v1alpha1.Application{
Status: v1alpha1.ApplicationStatus{Sync: v1alpha1.SyncStatus{ComparedTo: v1alpha1.ComparedTo{
Source: v1alpha1.ApplicationSource{
Helm: &v1alpha1.ApplicationSourceHelm{
ValuesObject: &runtime.RawExtension{
Object: &unstructured.Unstructured{Object: map[string]interface{}{"key": []string{"value-modified1"}}},
},
},
},
}}},
}
patch, _, err := createMergePatch(
app,
appModified)
require.NoError(t, err)
assert.Equal(t, `{"status":{"sync":{"comparedTo":{"source":{"helm":{"valuesObject":{"key":["value-modified1"]}}}}}}}`, string(patch))
}
func TestAppStatusIsReplaced(t *testing.T) {
original := &v1alpha1.ApplicationStatus{Sync: v1alpha1.SyncStatus{
ComparedTo: v1alpha1.ComparedTo{
Destination: v1alpha1.ApplicationDestination{
Server: "https://mycluster",
},
},
}}
updated := &v1alpha1.ApplicationStatus{Sync: v1alpha1.SyncStatus{
ComparedTo: v1alpha1.ComparedTo{
Destination: v1alpha1.ApplicationDestination{
Name: "mycluster",
},
},
}}
patchData, ok, err := createMergePatch(original, updated)
require.NoError(t, err)
require.True(t, ok)
patchObj := map[string]interface{}{}
require.NoError(t, json.Unmarshal(patchData, &patchObj))
val, has, err := unstructured.NestedFieldNoCopy(patchObj, "sync", "comparedTo", "destination", "server")
require.NoError(t, err)
require.True(t, has)
require.Nil(t, val)
}

View File

@@ -1,48 +1,83 @@
setTimeout(function() {
const callbackName = 'callback_' + new Date().getTime();
window[callbackName] = function (response) {
const div = document.createElement('div');
div.innerHTML = response.html;
document.querySelector(".md-header__inner > .md-header__title").appendChild(div);
const container = div.querySelector('.rst-versions');
var caret = document.createElement('div');
caret.innerHTML = "<i class='fa fa-caret-down dropdown-caret'></i>"
caret.classList.add('dropdown-caret')
div.querySelector('.rst-current-version').appendChild(caret);
const targetNode = document.querySelector('.md-header__inner');
const observerOptions = {
childList: true,
subtree: true
};
const observerCallback = function(mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
const titleElement = document.querySelector('.md-header__inner > .md-header__title');
if (titleElement) {
initializeVersionDropdown();
observer.disconnect();
}
}
}
};
const observer = new MutationObserver(observerCallback);
observer.observe(targetNode, observerOptions);
function getCurrentVersion() {
const currentVersion = window.location.href.match(/\/en\/(release-(?:v\d+|[\d\.]+|\w+)|latest|stable)\//);
if (currentVersion && currentVersion.length > 1) {
return currentVersion[1];
}
return null;
}
function initializeVersionDropdown() {
const callbackName = 'callback_' + new Date().getTime();
window[callbackName] = function(response) {
const div = document.createElement('div');
div.innerHTML = response.html;
document.querySelector(".md-header__inner > .md-header__title").appendChild(div);
const container = div.querySelector('.rst-versions');
var caret = document.createElement('div');
caret.innerHTML = "<i class='fa fa-caret-down dropdown-caret'></i>";
caret.classList.add('dropdown-caret');
div.querySelector('.rst-current-version').appendChild(caret);
div.querySelector('.rst-current-version').addEventListener('click', function() {
container.classList.toggle('shift-up');
});
};
var CSSLink = document.createElement('link');
CSSLink.rel='stylesheet';
CSSLink.rel = 'stylesheet';
CSSLink.href = '/assets/versions.css';
document.getElementsByTagName('head')[0].appendChild(CSSLink);
var script = document.createElement('script');
script.src = 'https://argo-cd.readthedocs.io/_/api/v2/footer_html/?'+
'callback=' + callbackName + '&project=argo-cd&page=&theme=mkdocs&format=jsonp&docroot=docs&source_suffix=.md&version=' + (window['READTHEDOCS_DATA'] || { version: 'latest' }).version;
const currentVersion = getCurrentVersion();
script.src = 'https://argo-cd.readthedocs.io/_/api/v2/footer_html/?' +
'callback=' + callbackName + '&project=argo-cd&page=&theme=mkdocs&format=jsonp&docroot=docs&source_suffix=.md&version=' + (currentVersion || 'latest');
document.getElementsByTagName('head')[0].appendChild(script);
}, 0);
}
// VERSION WARNINGS
window.addEventListener("DOMContentLoaded", function() {
var rtdData = window['READTHEDOCS_DATA'] || { version: 'latest' };
var margin = 30;
var headerHeight = document.getElementsByClassName("md-header")[0].offsetHeight;
if (rtdData.version === "latest") {
document.querySelector("div[data-md-component=announce]").innerHTML = "<div id='announce-msg'>You are viewing the docs for an unreleased version of Argo CD, <a href='https://argo-cd.readthedocs.io/en/stable/'>click here to go to the latest stable version.</a></div>"
var bannerHeight = document.getElementById('announce-msg').offsetHeight + margin
document.querySelector("header.md-header").style.top = bannerHeight +"px";
document.querySelector('style').textContent +=
"@media screen and (min-width: 76.25em){ .md-sidebar { height: 0; top:"+ (bannerHeight+headerHeight)+"px !important; }}"
document.querySelector('style').textContent +=
"@media screen and (min-width: 60em){ .md-sidebar--secondary { height: 0; top:"+ (bannerHeight+headerHeight)+"px !important; }}"
}
else if (rtdData.version !== "stable") {
document.querySelector("div[data-md-component=announce]").innerHTML = "<div id='announce-msg'>You are viewing the docs for a previous version of Argo CD, <a href='https://argo-cd.readthedocs.io/en/stable/'>click here to go to the latest stable version.</a></div>"
var bannerHeight = document.getElementById('announce-msg').offsetHeight + margin
document.querySelector("header.md-header").style.top = bannerHeight +"px";
document.querySelector('style').textContent +=
"@media screen and (min-width: 76.25em){ .md-sidebar { height: 0; top:"+ (bannerHeight+headerHeight)+"px !important; }}"
document.querySelector('style').textContent +=
"@media screen and (min-width: 60em){ .md-sidebar--secondary { height: 0; top:"+ (bannerHeight+headerHeight)+"px !important; }}"
var headerHeight = document.getElementsByClassName("md-header")[0].offsetHeight;
const currentVersion = getCurrentVersion();
if (currentVersion) {
if (currentVersion === "latest") {
document.querySelector("div[data-md-component=announce]").innerHTML = "<div id='announce-msg'>You are viewing the docs for an unreleased version of Argo CD, <a href='https://argo-cd.readthedocs.io/en/stable/'>click here to go to the latest stable version.</a></div>";
var bannerHeight = document.getElementById('announce-msg').offsetHeight + margin;
document.querySelector("header.md-header").style.top = bannerHeight + "px";
document.querySelector('style').textContent +=
"@media screen and (min-width: 76.25em){ .md-sidebar { height: 0; top:" + (bannerHeight + headerHeight) + "px !important; }}";
document.querySelector('style').textContent +=
"@media screen and (min-width: 60em){ .md-sidebar--secondary { height: 0; top:" + (bannerHeight + headerHeight) + "px !important; }}";
} else if (currentVersion !== "stable") {
document.querySelector("div[data-md-component=announce]").innerHTML = "<div id='announce-msg'>You are viewing the docs for a previous version of Argo CD, <a href='https://argo-cd.readthedocs.io/en/stable/'>click here to go to the latest stable version.</a></div>";
var bannerHeight = document.getElementById('announce-msg').offsetHeight + margin;
document.querySelector("header.md-header").style.top = bannerHeight + "px";
document.querySelector('style').textContent +=
"@media screen and (min-width: 76.25em){ .md-sidebar { height: 0; top:" + (bannerHeight + headerHeight) + "px !important; }}";
document.querySelector('style').textContent +=
"@media screen and (min-width: 60em){ .md-sidebar--secondary { height: 0; top:" + (bannerHeight + headerHeight) + "px !important; }}";
}
}
});

View File

@@ -326,7 +326,7 @@ As with other generators, clusters *must* already be defined within Argo CD, in
In addition to the flattened key/value pairs from the configuration file, the following generator parameters are provided:
- `{{.path.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`
- `{{index .path.segments n}}`: The path to the matching configuration file within the Git repository, split into array elements (`n` - array index). Example: `index .path.segments 0: clusters`, `index .path.segments 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.
@@ -360,7 +360,7 @@ spec:
files:
- path: "applicationset/examples/git-generator-files-discovery/cluster-config/**/config.json"
values:
base_dir: "{{index .path 0}}/{{index .path 1}}/{{index .path 2}}"
base_dir: "{{index .path.segments 0}}/{{index .path.segments 1}}/{{index .path.segments 2}}"
template:
metadata:
name: '{{.cluster.name}}-guestbook'

View File

@@ -412,3 +412,5 @@ data:
cluster:
name: some-cluster
server: https://some-cluster
# The maximum size of the payload that can be sent to the webhook server.
webhook.maxPayloadSizeMB: 1024

View File

@@ -3,3 +3,56 @@
## Upgraded Kustomize Version
Note that bundled Kustomize version has been upgraded from 5.1.0 to 5.2.1.
## Egress NetworkPolicy for `argocd-redis` and `argocd-redis-ha-haproxy`
Starting with Argo CD 2.9.16, the NetworkPolicy for the `argocd-redis` and `argocd-redis-ha-haproxy` dropped Egress restrictions. This change was made
to allow access to the Kubernetes API to create a secret to secure Redis access.
To retain similar networking restrictions as before 2.9.16, you can add an Egress rule to allow access only to the
Kubernetes API and access needed by Redis itself. The Egress rule for Kubernetes access will depend entirely on your
Kubernetes setup. The access for Redis itself can be allowed by adding the following to the
`argocd-redis-network-policy` NetworkPolicy:
```diff
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: argocd-redis-network-policy
spec:
policyTypes:
- Ingress
+ - Egress
+ egress:
+ - ports:
+ - port: 53
+ protocol: UDP
+ - port: 53
+ protocol: TCP
```
```diff
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: argocd-redis-ha-haproxy
spec:
policyTypes:
- Ingress
+ - Egress
+ egress:
+ - ports:
+ - port: 6379
+ protocol: TCP
+ - port: 26379
+ protocol: TCP
+ to:
+ - podSelector:
+ matchLabels:
+ app.kubernetes.io/name: argocd-redis-ha
+ - ports:
+ - port: 53
+ protocol: UDP
+ - port: 53
+ protocol: TCP
```

View File

@@ -14,3 +14,65 @@ 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.
## Egress NetworkPolicy for `argocd-redis` and `argocd-redis-ha-haproxy`
Starting with Argo CD 2.10.11, the NetworkPolicy for the `argocd-redis` and `argocd-redis-ha-haproxy` dropped Egress restrictions. This change was made
to allow access to the Kubernetes API to create a secret to secure Redis access.
To retain similar networking restrictions as before 2.10.11, you can add an Egress rule to allow access only to the
Kubernetes API and access needed by Redis itself. The Egress rule for Kubernetes access will depend entirely on your
Kubernetes setup. The access for Redis itself can be allowed by adding the following to the
`argocd-redis-network-policy` NetworkPolicy:
```diff
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: argocd-redis-network-policy
spec:
policyTypes:
- Ingress
+ - Egress
+ egress:
+ - ports:
+ - port: 53
+ protocol: UDP
+ - port: 53
+ protocol: TCP
```
```diff
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: argocd-redis-ha-haproxy
spec:
policyTypes:
- Ingress
+ - Egress
+ egress:
+ - ports:
+ - port: 6379
+ protocol: TCP
+ - port: 26379
+ protocol: TCP
+ to:
+ - podSelector:
+ matchLabels:
+ app.kubernetes.io/name: argocd-redis-ha
+ - ports:
+ - port: 53
+ protocol: UDP
+ - port: 53
+ protocol: TCP
```
## Sanitized project API response
Due to security reasons ([GHSA-786q-9hcg-v9ff](https://github.com/argoproj/argo-cd/security/advisories/GHSA-786q-9hcg-v9ff)),
the project API response was sanitized to remove sensitive information. This includes
credentials of project-scoped repositories and clusters.
> **Note:** The 2.10 series has been EOL for some time and has not received security updates. 2.10.18 was patched for critical
> CVE-2025-55190 but was not patched for other vulnerabilities. It is important to upgrade to a supported version as quickly as possible.

View File

@@ -19,6 +19,8 @@ URL configured in the Git provider should use the `/api/webhook` endpoint of you
(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.
To prevent DDoS attacks with unauthenticated webhook events (the `/api/webhook` endpoint currently lacks rate limiting protection), it is recommended to limit the payload size. You can achieve this by configuring the `argocd-cm` ConfigMap with the `webhook.maxPayloadSizeMB` attribute. The default value is 1GB.
## Github
![Add Webhook](../assets/webhook-config.png "Add Webhook")

10
go.mod
View File

@@ -13,7 +13,7 @@ require (
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
github.com/alicebob/miniredis/v2 v2.30.4
github.com/antonmedv/expr v1.15.2
github.com/argoproj/gitops-engine v0.7.1-0.20240416142647-fbecbb86e412
github.com/argoproj/gitops-engine v0.7.1-0.20240715141017-b6ec82aedce5
github.com/argoproj/notifications-engine v0.4.1-0.20240126143042-84b9f7913604
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1
github.com/aws/aws-sdk-go v1.50.8
@@ -51,14 +51,14 @@ require (
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.4
github.com/hashicorp/go-retryablehttp v0.7.7
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.67
github.com/mattn/go-isatty v0.0.19
github.com/mattn/go-isatty v0.0.20
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
@@ -77,7 +77,7 @@ require (
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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1
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
@@ -268,7 +268,7 @@ require (
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/sys v0.20.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

27
go.sum
View File

@@ -694,8 +694,8 @@ github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb
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.20240416142647-fbecbb86e412 h1:je2wJpWtaoS55mA5MBPCeDnKMeF42pkxO9Oa5KbWrdg=
github.com/argoproj/gitops-engine v0.7.1-0.20240416142647-fbecbb86e412/go.mod h1:gWE8uROi7hIkWGNAVM+8FWkMfo0vZ03SLx/aFw/DBzg=
github.com/argoproj/gitops-engine v0.7.1-0.20240715141017-b6ec82aedce5 h1:YF0xxjIYPeZfsKfZtTd7rxEWQ7EeiTBJHO3PmQ2kV3c=
github.com/argoproj/gitops-engine v0.7.1-0.20240715141017-b6ec82aedce5/go.mod h1:d4eLldeEFyZIcVySAMhXhnh1tTa4qfvPYfut9B8UClw=
github.com/argoproj/notifications-engine v0.4.1-0.20240126143042-84b9f7913604 h1:pMfBao6Vm1Ax0xGIp9BWEia2nKkccHwV0dTEdrsFOpo=
github.com/argoproj/notifications-engine v0.4.1-0.20240126143042-84b9f7913604/go.mod h1:TsyusmXQWIL0ST7YMRG/ered7WlWDmbmnPpXnS2LJmM=
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 h1:qsHwwOJ21K2Ao0xPju1sNuqphyMnMYkyB3ZLoLtxWpo=
@@ -891,6 +891,8 @@ 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.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
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=
@@ -1239,14 +1241,14 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
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.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
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=
@@ -1381,13 +1383,15 @@ github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsI
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
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.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
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.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/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.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@@ -1746,8 +1750,8 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
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=
@@ -2134,8 +2138,9 @@ 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/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.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=

View File

@@ -5,7 +5,7 @@ kind: Kustomization
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.10.10
newTag: v2.10.20
resources:
- ./application-controller
- ./dex

View File

@@ -8,7 +8,6 @@ spec:
app.kubernetes.io/name: argocd-redis
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
@@ -23,9 +22,3 @@ spec:
ports:
- protocol: TCP
port: 6379
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP

View File

@@ -21060,7 +21060,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -21178,7 +21178,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -21413,7 +21413,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -21465,7 +21465,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -21737,7 +21737,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-application-controller
ports:
@@ -21819,12 +21819,6 @@ kind: NetworkPolicy
metadata:
name: argocd-redis-network-policy
spec:
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
ingress:
- from:
- podSelector:
@@ -21844,7 +21838,6 @@ spec:
app.kubernetes.io/name: argocd-redis
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy

View File

@@ -12,4 +12,4 @@ resources:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.10.10
newTag: v2.10.20

View File

@@ -12,7 +12,7 @@ patches:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.10.10
newTag: v2.10.20
resources:
- ../../base/application-controller
- ../../base/applicationset-controller

View File

@@ -8,7 +8,6 @@ spec:
app.kubernetes.io/name: argocd-redis-ha-haproxy
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
@@ -25,18 +24,4 @@ spec:
protocol: TCP
- port: 26379
protocol: TCP
egress:
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: argocd-redis-ha
ports:
- port: 6379
protocol: TCP
- port: 26379
protocol: TCP
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP

View File

@@ -1091,7 +1091,7 @@ spec:
topologyKey: kubernetes.io/hostname
initContainers:
- name: config-init
image: public.ecr.aws/docker/library/haproxy:2.6.14-alpine
image: haproxy:2.6.14-alpine
imagePullPolicy: IfNotPresent
resources:
{}
@@ -1115,7 +1115,7 @@ spec:
mountPath: /data
containers:
- name: haproxy
image: public.ecr.aws/docker/library/haproxy:2.6.14-alpine
image: haproxy:2.6.14-alpine
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
@@ -1219,7 +1219,7 @@ spec:
automountServiceAccountToken: false
initContainers:
- name: config-init
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
resources:
{}
@@ -1258,7 +1258,7 @@ spec:
containers:
- name: redis
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
command:
- redis-server
@@ -1321,7 +1321,7 @@ spec:
- /bin/sh
- /readonly-config/trigger-failover-if-master.sh
- name: sentinel
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
command:
- redis-sentinel
@@ -1378,7 +1378,7 @@ spec:
{}
- name: split-brain-fix
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
command:
- sh

View File

@@ -14,6 +14,7 @@ redis-ha:
IPv6:
enabled: false
image:
repository: haproxy
tag: 2.6.14-alpine
containerSecurityContext: null
timeout:
@@ -23,6 +24,7 @@ redis-ha:
metrics:
enabled: true
image:
repository: redis
tag: 7.0.15-alpine
containerSecurityContext: null
sentinel:

View File

@@ -22401,7 +22401,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -22524,7 +22524,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -22606,7 +22606,7 @@ spec:
key: notificationscontroller.selfservice.enabled
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -22686,7 +22686,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/haproxy:2.6.14-alpine
image: haproxy:2.6.14-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -22725,7 +22725,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -22741,7 +22741,7 @@ spec:
- /readonly/haproxy_init.sh
command:
- sh
image: public.ecr.aws/docker/library/haproxy:2.6.14-alpine
image: haproxy:2.6.14-alpine
imagePullPolicy: IfNotPresent
name: config-init
securityContext:
@@ -22988,7 +22988,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -23040,7 +23040,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -23364,7 +23364,7 @@ spec:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -23663,7 +23663,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-application-controller
ports:
@@ -23746,7 +23746,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
@@ -23806,7 +23806,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -23864,7 +23864,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
name: split-brain-fix
resources: {}
@@ -23899,7 +23899,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
name: config-init
securityContext:
@@ -24022,21 +24022,6 @@ kind: NetworkPolicy
metadata:
name: argocd-redis-ha-proxy-network-policy
spec:
egress:
- ports:
- port: 6379
protocol: TCP
- port: 26379
protocol: TCP
to:
- podSelector:
matchLabels:
app.kubernetes.io/name: argocd-redis-ha
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
ingress:
- from:
- podSelector:
@@ -24058,7 +24043,6 @@ spec:
app.kubernetes.io/name: argocd-redis-ha-haproxy
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy

View File

@@ -1686,7 +1686,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -1809,7 +1809,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1891,7 +1891,7 @@ spec:
key: notificationscontroller.selfservice.enabled
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -1971,7 +1971,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/haproxy:2.6.14-alpine
image: haproxy:2.6.14-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -2010,7 +2010,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -2026,7 +2026,7 @@ spec:
- /readonly/haproxy_init.sh
command:
- sh
image: public.ecr.aws/docker/library/haproxy:2.6.14-alpine
image: haproxy:2.6.14-alpine
imagePullPolicy: IfNotPresent
name: config-init
securityContext:
@@ -2273,7 +2273,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -2325,7 +2325,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -2649,7 +2649,7 @@ spec:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2948,7 +2948,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-application-controller
ports:
@@ -3031,7 +3031,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
@@ -3091,7 +3091,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
lifecycle: {}
livenessProbe:
@@ -3149,7 +3149,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
name: split-brain-fix
resources: {}
@@ -3184,7 +3184,7 @@ spec:
secretKeyRef:
key: auth
name: argocd-redis
image: public.ecr.aws/docker/library/redis:7.0.15-alpine
image: redis:7.0.15-alpine
imagePullPolicy: IfNotPresent
name: config-init
securityContext:
@@ -3307,21 +3307,6 @@ kind: NetworkPolicy
metadata:
name: argocd-redis-ha-proxy-network-policy
spec:
egress:
- ports:
- port: 6379
protocol: TCP
- port: 26379
protocol: TCP
to:
- podSelector:
matchLabels:
app.kubernetes.io/name: argocd-redis-ha
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
ingress:
- from:
- podSelector:
@@ -3343,7 +3328,6 @@ spec:
app.kubernetes.io/name: argocd-redis-ha-haproxy
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy

View File

@@ -21518,7 +21518,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -21641,7 +21641,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -21723,7 +21723,7 @@ spec:
key: notificationscontroller.selfservice.enabled
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -21823,7 +21823,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -22058,7 +22058,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -22110,7 +22110,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -22432,7 +22432,7 @@ spec:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -22731,7 +22731,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-application-controller
ports:
@@ -22860,12 +22860,6 @@ kind: NetworkPolicy
metadata:
name: argocd-redis-network-policy
spec:
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
ingress:
- from:
- podSelector:
@@ -22885,7 +22879,6 @@ spec:
app.kubernetes.io/name: argocd-redis
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy

View File

@@ -803,7 +803,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -926,7 +926,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1008,7 +1008,7 @@ spec:
key: notificationscontroller.selfservice.enabled
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -1108,7 +1108,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -1343,7 +1343,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1395,7 +1395,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -1717,7 +1717,7 @@ spec:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2016,7 +2016,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.10.10
image: quay.io/argoproj/argocd:v2.10.20
imagePullPolicy: Always
name: argocd-application-controller
ports:
@@ -2145,12 +2145,6 @@ kind: NetworkPolicy
metadata:
name: argocd-redis-network-policy
spec:
egress:
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
ingress:
- from:
- podSelector:
@@ -2170,7 +2164,6 @@ spec:
app.kubernetes.io/name: argocd-redis
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy

View File

@@ -2218,7 +2218,6 @@ message SyncStatus {
optional string status = 1;
// ComparedTo contains information about what has been compared
// +patchStrategy=replace
optional ComparedTo comparedTo = 2;
// Revision contains information about the revision the comparison has been performed to

View File

@@ -7684,11 +7684,6 @@ func schema_pkg_apis_application_v1alpha1_SyncStatus(ref common.ReferenceCallbac
},
},
"comparedTo": {
VendorExtensible: spec.VendorExtensible{
Extensions: spec.Extensions{
"x-kubernetes-patch-strategy": "replace",
},
},
SchemaProps: spec.SchemaProps{
Description: "ComparedTo contains information about what has been compared",
Default: map[string]interface{}{},

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"net/url"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/util/cert"
"github.com/argoproj/argo-cd/v2/util/git"
"github.com/argoproj/argo-cd/v2/util/helm"
@@ -274,6 +275,32 @@ func (m *Repository) StringForLogging() string {
return fmt.Sprintf("&Repository{Repo: %q, Type: %q, Name: %q, Project: %q}", m.Repo, m.Type, m.Name, m.Project)
}
// Sanitized returns a copy of the Repository with sensitive information removed.
func (repo *Repository) Sanitized() *Repository {
return &Repository{
Repo: repo.Repo,
Type: repo.Type,
Name: repo.Name,
Insecure: repo.IsInsecure(),
EnableLFS: repo.EnableLFS,
EnableOCI: repo.EnableOCI,
Proxy: repo.Proxy,
Project: repo.Project,
ForceHttpBasicAuth: repo.ForceHttpBasicAuth,
InheritedCreds: repo.InheritedCreds,
GithubAppId: repo.GithubAppId,
GithubAppInstallationId: repo.GithubAppInstallationId,
GitHubAppEnterpriseBaseURL: repo.GitHubAppEnterpriseBaseURL,
}
}
func (repo *Repository) Normalize() *Repository {
if repo.Type == "" {
repo.Type = common.DefaultRepoType
}
return repo
}
// Repositories defines a list of Repository configurations
type Repositories []*Repository

View File

@@ -1497,8 +1497,7 @@ type SyncStatus struct {
// Status is the sync state of the comparison
Status SyncStatusCode `json:"status" protobuf:"bytes,1,opt,name=status,casttype=SyncStatusCode"`
// ComparedTo contains information about what has been compared
// +patchStrategy=replace
ComparedTo ComparedTo `json:"comparedTo,omitempty" protobuf:"bytes,2,opt,name=comparedTo" patchStrategy:"replace"`
ComparedTo ComparedTo `json:"comparedTo,omitempty" protobuf:"bytes,2,opt,name=comparedTo"`
// Revision contains information about the revision the comparison has been performed to
Revision string `json:"revision,omitempty" protobuf:"bytes,3,opt,name=revision"`
// Revisions contains information about the revisions of multiple sources the comparison has been performed to
@@ -1772,6 +1771,30 @@ type Cluster struct {
Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,13,opt,name=annotations"`
}
func (c *Cluster) Sanitized() *Cluster {
return &Cluster{
ID: c.ID,
Server: c.Server,
Name: c.Name,
Project: c.Project,
Namespaces: c.Namespaces,
Shard: c.Shard,
Labels: c.Labels,
Annotations: c.Annotations,
ClusterResources: c.ClusterResources,
ConnectionState: c.ConnectionState,
ServerVersion: c.ServerVersion,
Info: c.Info,
RefreshRequestedAt: c.RefreshRequestedAt,
Config: ClusterConfig{
AWSAuthConfig: c.Config.AWSAuthConfig,
TLSClientConfig: TLSClientConfig{
Insecure: c.Config.Insecure,
},
},
}
}
// Equals returns true if two cluster objects are considered to be equal
func (c *Cluster) Equals(other *Cluster) bool {
if c.Server != other.Server {

View File

@@ -11,13 +11,9 @@ import (
"testing"
"time"
"github.com/argoproj/gitops-engine/pkg/diff"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
argocdcommon "github.com/argoproj/argo-cd/v2/common"
"github.com/stretchr/testify/require"
"k8s.io/utils/pointer"
"github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/stretchr/testify/assert"
@@ -3624,34 +3620,57 @@ func TestOptionalMapEquality(t *testing.T) {
}
}
func TestHelmValuesObjectHasReplaceStrategy(t *testing.T) {
app := Application{
Status: ApplicationStatus{Sync: SyncStatus{ComparedTo: ComparedTo{
Source: ApplicationSource{
Helm: &ApplicationSourceHelm{
ValuesObject: &runtime.RawExtension{
Object: &unstructured.Unstructured{Object: map[string]interface{}{"key": []string{"value"}}},
},
},
func TestSanitized(t *testing.T) {
now := metav1.Now()
cluster := &Cluster{
ID: "123",
Server: "https://example.com",
Name: "example",
ServerVersion: "v1.0.0",
Namespaces: []string{"default", "kube-system"},
Project: "default",
Labels: map[string]string{
"env": "production",
},
Annotations: map[string]string{
"annotation-key": "annotation-value",
},
ConnectionState: ConnectionState{
Status: ConnectionStatusSuccessful,
Message: "Connection successful",
ModifiedAt: &now,
},
Config: ClusterConfig{
Username: "admin",
Password: "password123",
BearerToken: "abc",
TLSClientConfig: TLSClientConfig{
Insecure: true,
},
}}},
ExecProviderConfig: &ExecProviderConfig{
Command: "test",
},
},
}
appModified := Application{
Status: ApplicationStatus{Sync: SyncStatus{ComparedTo: ComparedTo{
Source: ApplicationSource{
Helm: &ApplicationSourceHelm{
ValuesObject: &runtime.RawExtension{
Object: &unstructured.Unstructured{Object: map[string]interface{}{"key": []string{"value-modified1"}}},
},
},
assert.Equal(t, &Cluster{
ID: "123",
Server: "https://example.com",
Name: "example",
ServerVersion: "v1.0.0",
Namespaces: []string{"default", "kube-system"},
Project: "default",
Labels: map[string]string{"env": "production"},
Annotations: map[string]string{"annotation-key": "annotation-value"},
ConnectionState: ConnectionState{
Status: ConnectionStatusSuccessful,
Message: "Connection successful",
ModifiedAt: &now,
},
Config: ClusterConfig{
TLSClientConfig: TLSClientConfig{
Insecure: true,
},
}}},
}
patch, _, err := diff.CreateTwoWayMergePatch(
app,
appModified, Application{})
require.NoError(t, err)
assert.Equal(t, `{"status":{"sync":{"comparedTo":{"destination":{},"source":{"helm":{"valuesObject":{"key":["value-modified1"]}},"repoURL":""}}}}}`, string(patch))
},
}, cluster.Sanitized())
}

View File

@@ -70,13 +70,13 @@ func NewServer(metricsServer *metrics.MetricsServer, cache *reposervercache.Cach
serverLog := log.NewEntry(log.StandardLogger())
streamInterceptors := []grpc.StreamServerInterceptor{
otelgrpc.StreamServerInterceptor(),
otelgrpc.StreamServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
grpc_logrus.StreamServerInterceptor(serverLog),
grpc_prometheus.StreamServerInterceptor,
grpc_util.PanicLoggerStreamServerInterceptor(serverLog),
}
unaryInterceptors := []grpc.UnaryServerInterceptor{
otelgrpc.UnaryServerInterceptor(),
otelgrpc.UnaryServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
grpc_logrus.UnaryServerInterceptor(serverLog),
grpc_prometheus.UnaryServerInterceptor,
grpc_util.PanicLoggerUnaryServerInterceptor(serverLog),

View File

@@ -225,7 +225,7 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fieldLog.Info("terminal session starting")
session, err := newTerminalSession(w, r, nil, s.sessionManager)
session, err := newTerminalSession(ctx, w, r, nil, s.sessionManager, appRBACName, s.enf)
if err != nil {
http.Error(w, "Failed to start terminal session", http.StatusBadRequest)
return

View File

@@ -1,15 +1,19 @@
package application
import (
"context"
"encoding/json"
"fmt"
"github.com/argoproj/argo-cd/v2/common"
httputil "github.com/argoproj/argo-cd/v2/util/http"
util_session "github.com/argoproj/argo-cd/v2/util/session"
"net/http"
"sync"
"time"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
httputil "github.com/argoproj/argo-cd/v2/util/http"
"github.com/argoproj/argo-cd/v2/util/rbac"
util_session "github.com/argoproj/argo-cd/v2/util/session"
"github.com/gorilla/websocket"
log "github.com/sirupsen/logrus"
"k8s.io/client-go/tools/remotecommand"
@@ -31,6 +35,7 @@ var upgrader = func() websocket.Upgrader {
// terminalSession implements PtyHandler
type terminalSession struct {
ctx context.Context
wsConn *websocket.Conn
sizeChan chan remotecommand.TerminalSize
doneChan chan struct{}
@@ -39,6 +44,8 @@ type terminalSession struct {
writeLock sync.Mutex
sessionManager *util_session.SessionManager
token *string
appRBACName string
enf *rbac.Enforcer
}
// getToken get auth token from web socket request
@@ -48,7 +55,7 @@ func getToken(r *http.Request) (string, error) {
}
// newTerminalSession create terminalSession
func newTerminalSession(w http.ResponseWriter, r *http.Request, responseHeader http.Header, sessionManager *util_session.SessionManager) (*terminalSession, error) {
func newTerminalSession(ctx context.Context, w http.ResponseWriter, r *http.Request, responseHeader http.Header, sessionManager *util_session.SessionManager, appRBACName string, enf *rbac.Enforcer) (*terminalSession, error) {
token, err := getToken(r)
if err != nil {
return nil, err
@@ -59,12 +66,15 @@ func newTerminalSession(w http.ResponseWriter, r *http.Request, responseHeader h
return nil, err
}
session := &terminalSession{
ctx: ctx,
wsConn: conn,
tty: true,
sizeChan: make(chan remotecommand.TerminalSize),
doneChan: make(chan struct{}),
sessionManager: sessionManager,
token: &token,
appRBACName: appRBACName,
enf: enf,
}
return session, nil
}
@@ -125,6 +135,29 @@ func (t *terminalSession) reconnect() (int, error) {
return 0, nil
}
func (t *terminalSession) validatePermissions(p []byte) (int, error) {
permissionDeniedMessage, _ := json.Marshal(TerminalMessage{
Operation: "stdout",
Data: "Permission denied",
})
if err := t.enf.EnforceErr(t.ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, t.appRBACName); err != nil {
err = t.wsConn.WriteMessage(websocket.TextMessage, permissionDeniedMessage)
if err != nil {
log.Errorf("permission denied message err: %v", err)
}
return copy(p, EndOfTransmission), permissionDeniedErr
}
if err := t.enf.EnforceErr(t.ctx.Value("claims"), rbacpolicy.ResourceExec, rbacpolicy.ActionCreate, t.appRBACName); err != nil {
err = t.wsConn.WriteMessage(websocket.TextMessage, permissionDeniedMessage)
if err != nil {
log.Errorf("permission denied message err: %v", err)
}
return copy(p, EndOfTransmission), permissionDeniedErr
}
return 0, nil
}
// Read called in a loop from remotecommand as long as the process is running
func (t *terminalSession) Read(p []byte) (int, error) {
// check if token still valid
@@ -135,6 +168,12 @@ func (t *terminalSession) Read(p []byte) (int, error) {
return t.reconnect()
}
// validate permissions
code, err := t.validatePermissions(p)
if err != nil {
return code, err
}
t.readLock.Lock()
_, message, err := t.wsConn.ReadMessage()
t.readLock.Unlock()

View File

@@ -1,28 +1,69 @@
package application
import (
"context"
"encoding/json"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"strings"
"testing"
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/common"
"github.com/argoproj/argo-cd/v2/util/assets"
"github.com/argoproj/argo-cd/v2/util/rbac"
"github.com/golang-jwt/jwt/v4"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func reconnect(w http.ResponseWriter, r *http.Request) {
func newTestTerminalSession(w http.ResponseWriter, r *http.Request) terminalSession {
var upgrader = websocket.Upgrader{}
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
return terminalSession{}
}
ts := terminalSession{wsConn: c}
return terminalSession{wsConn: c}
}
func newEnforcer() *rbac.Enforcer {
additionalConfig := make(map[string]string, 0)
kubeclientset := fake.NewSimpleClientset(&v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: testNamespace,
Name: "argocd-cm",
Labels: map[string]string{
"app.kubernetes.io/part-of": "argocd",
},
},
Data: additionalConfig,
}, &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "argocd-secret",
Namespace: testNamespace,
},
Data: map[string][]byte{
"admin.password": []byte("test"),
"server.secretkey": []byte("test"),
},
})
enforcer := rbac.NewEnforcer(kubeclientset, testNamespace, common.ArgoCDRBACConfigMapName, nil)
return enforcer
}
func reconnect(w http.ResponseWriter, r *http.Request) {
ts := newTestTerminalSession(w, r)
_, _ = ts.reconnect()
}
func TestReconnect(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(reconnect))
defer s.Close()
@@ -30,7 +71,7 @@ func TestReconnect(t *testing.T) {
// Connect to the server
ws, _, err := websocket.DefaultDialer.Dial(u, nil)
assert.NoError(t, err)
require.NoError(t, err)
defer ws.Close()
@@ -40,7 +81,74 @@ func TestReconnect(t *testing.T) {
err = json.Unmarshal(p, &message)
assert.NoError(t, err)
assert.Equal(t, message.Data, ReconnectMessage)
require.NoError(t, err)
assert.Equal(t, ReconnectMessage, message.Data)
}
func TestValidateWithAdminPermissions(t *testing.T) {
validate := func(w http.ResponseWriter, r *http.Request) {
enf := newEnforcer()
_ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
enf.SetDefaultRole("role:admin")
enf.SetClaimsEnforcerFunc(func(claims jwt.Claims, rvals ...interface{}) bool {
return true
})
ts := newTestTerminalSession(w, r)
ts.enf = enf
ts.appRBACName = "test"
// nolint:staticcheck
ts.ctx = context.WithValue(context.Background(), "claims", &jwt.MapClaims{"groups": []string{"admin"}})
_, err := ts.validatePermissions([]byte{})
require.NoError(t, err)
}
s := httptest.NewServer(http.HandlerFunc(validate))
defer s.Close()
u := "ws" + strings.TrimPrefix(s.URL, "http")
// Connect to the server
ws, _, err := websocket.DefaultDialer.Dial(u, nil)
require.NoError(t, err)
defer ws.Close()
}
func TestValidateWithoutPermissions(t *testing.T) {
validate := func(w http.ResponseWriter, r *http.Request) {
enf := newEnforcer()
_ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
enf.SetDefaultRole("role:test")
enf.SetClaimsEnforcerFunc(func(claims jwt.Claims, rvals ...interface{}) bool {
return false
})
ts := newTestTerminalSession(w, r)
ts.enf = enf
ts.appRBACName = "test"
// nolint:staticcheck
ts.ctx = context.WithValue(context.Background(), "claims", &jwt.MapClaims{"groups": []string{"test"}})
_, err := ts.validatePermissions([]byte{})
require.Error(t, err)
assert.Equal(t, permissionDeniedErr.Error(), err.Error())
}
s := httptest.NewServer(http.HandlerFunc(validate))
defer s.Close()
u := "ws" + strings.TrimPrefix(s.URL, "http")
// Connect to the server
ws, _, err := websocket.DefaultDialer.Dial(u, nil)
require.NoError(t, err)
defer ws.Close()
_, p, _ := ws.ReadMessage()
var message TerminalMessage
err = json.Unmarshal(p, &message)
require.NoError(t, err)
assert.Equal(t, "Permission denied", message.Data)
}

View File

@@ -187,15 +187,11 @@ func (s *Server) Create(ctx context.Context, q *cluster.ClusterCreateRequest) (*
// Get returns a cluster from a query
func (s *Server) Get(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
c, err := s.getClusterWith403IfNotExist(ctx, q)
c, err := s.getClusterAndVerifyAccess(ctx, q, rbacpolicy.ActionGet)
if err != nil {
return nil, err
}
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionGet, CreateClusterRBACObject(c.Project, q.Server)); err != nil {
return nil, err
}
return s.toAPIResponse(c), nil
}
@@ -207,6 +203,21 @@ func (s *Server) getClusterWith403IfNotExist(ctx context.Context, q *cluster.Clu
return repo, nil
}
func (s *Server) getClusterAndVerifyAccess(ctx context.Context, q *cluster.ClusterQuery, action string) (*appv1.Cluster, error) {
c, err := s.getClusterWith403IfNotExist(ctx, q)
if err != nil {
return nil, err
}
// verify that user can do the specified action inside project where cluster is located
if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, action, CreateClusterRBACObject(c.Project, c.Server)) {
log.WithField("cluster", q.Server).Warnf("encountered permissions issue while processing request: %v", err)
return nil, common.PermissionDeniedAPIError
}
return c, nil
}
func (s *Server) getCluster(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
if q.Id != nil {
q.Server = ""
@@ -278,20 +289,16 @@ var clusterFieldsByPath = map[string]func(updated *appv1.Cluster, existing *appv
// Update updates a cluster
func (s *Server) Update(ctx context.Context, q *cluster.ClusterUpdateRequest) (*appv1.Cluster, error) {
c, err := s.getClusterWith403IfNotExist(ctx, &cluster.ClusterQuery{
c, err := s.getClusterAndVerifyAccess(ctx, &cluster.ClusterQuery{
Server: q.Cluster.Server,
Name: q.Cluster.Name,
Id: q.Id,
})
}, rbacpolicy.ActionUpdate)
if err != nil {
return nil, err
}
// verify that user can do update inside project where cluster is located
if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(c.Project, c.Server)) {
return nil, common.PermissionDeniedAPIError
}
if len(q.UpdatedFields) == 0 || sets.NewString(q.UpdatedFields...).Has("project") {
// verify that user can do update inside project where cluster will be located
if !s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(q.Cluster.Project, c.Server)) {
@@ -341,7 +348,8 @@ func (s *Server) Delete(ctx context.Context, q *cluster.ClusterQuery) (*cluster.
if q.Name != "" {
servers, err := s.db.GetClusterServersByName(ctx, q.Name)
if err != nil {
return nil, err
log.WithField("cluster", q.Name).Warnf("failed to get cluster servers by name: %v", err)
return nil, common.PermissionDeniedAPIError
}
for _, server := range servers {
if err := enforceAndDelete(s, ctx, server, c.Project); err != nil {
@@ -359,7 +367,8 @@ func (s *Server) Delete(ctx context.Context, q *cluster.ClusterQuery) (*cluster.
func enforceAndDelete(s *Server, ctx context.Context, server, project string) error {
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionDelete, CreateClusterRBACObject(project, server)); err != nil {
return err
log.WithField("cluster", server).Warnf("encountered permissions issue while processing request: %v", err)
return common.PermissionDeniedAPIError
}
if err := s.db.DeleteCluster(ctx, server); err != nil {
return err
@@ -378,16 +387,19 @@ func (s *Server) RotateAuth(ctx context.Context, q *cluster.ClusterQuery) (*clus
if q.Name != "" {
servers, err = s.db.GetClusterServersByName(ctx, q.Name)
if err != nil {
return nil, status.Errorf(codes.NotFound, "failed to get cluster servers by name: %v", err)
log.WithField("cluster", q.Name).Warnf("failed to get cluster servers by name: %v", err)
return nil, common.PermissionDeniedAPIError
}
for _, server := range servers {
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(clust.Project, server)); err != nil {
return nil, status.Errorf(codes.PermissionDenied, "encountered permissions issue while processing request: %v", err)
log.WithField("cluster", server).Warnf("encountered permissions issue while processing request: %v", err)
return nil, common.PermissionDeniedAPIError
}
}
} else {
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(clust.Project, q.Server)); err != nil {
return nil, status.Errorf(codes.PermissionDenied, "encountered permissions issue while processing request: %v", err)
log.WithField("cluster", q.Server).Warnf("encountered permissions issue while processing request: %v", err)
return nil, common.PermissionDeniedAPIError
}
servers = append(servers, q.Server)
}
@@ -446,19 +458,8 @@ func (s *Server) RotateAuth(ctx context.Context, q *cluster.ClusterQuery) (*clus
}
func (s *Server) toAPIResponse(clust *appv1.Cluster) *appv1.Cluster {
clust = clust.Sanitized()
_ = s.cache.GetClusterInfo(clust.Server, &clust.Info)
clust.Config.Password = ""
clust.Config.BearerToken = ""
clust.Config.TLSClientConfig.KeyData = nil
if clust.Config.ExecProviderConfig != nil {
// We can't know what the user has put into args or
// env vars on the exec provider that might be sensitive
// (e.g. --private-key=XXX, PASSWORD=XXX)
// Implicitly assumes the command executable name is non-sensitive
clust.Config.ExecProviderConfig.Env = make(map[string]string)
clust.Config.ExecProviderConfig.Args = nil
}
// populate deprecated fields for backward compatibility
clust.ServerVersion = clust.Info.ServerVersion
clust.ConnectionState = clust.Info.ConnectionState
@@ -467,13 +468,10 @@ func (s *Server) toAPIResponse(clust *appv1.Cluster) *appv1.Cluster {
// InvalidateCache invalidates cluster cache
func (s *Server) InvalidateCache(ctx context.Context, q *cluster.ClusterQuery) (*appv1.Cluster, error) {
cls, err := s.getClusterWith403IfNotExist(ctx, q)
cls, err := s.getClusterAndVerifyAccess(ctx, q, rbacpolicy.ActionUpdate)
if err != nil {
return nil, err
}
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceClusters, rbacpolicy.ActionUpdate, CreateClusterRBACObject(cls.Project, q.Server)); err != nil {
return nil, err
}
now := v1.Now()
cls.RefreshRequestedAt = &now
cls, err = s.db.UpdateCluster(ctx, cls)

View File

@@ -4,6 +4,9 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
"github.com/argoproj/argo-cd/v2/util/assets"
"github.com/golang-jwt/jwt/v4"
"reflect"
"testing"
"time"
@@ -51,6 +54,16 @@ func newNoopEnforcer() *rbac.Enforcer {
return enf
}
func newEnforcer() *rbac.Enforcer {
enforcer := rbac.NewEnforcer(fake.NewSimpleClientset(test.NewFakeConfigMap()), test.FakeArgoCDNamespace, common.ArgoCDRBACConfigMapName, nil)
_ = enforcer.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
enforcer.SetDefaultRole("role:test")
enforcer.SetClaimsEnforcerFunc(func(claims jwt.Claims, rvals ...interface{}) bool {
return true
})
return enforcer
}
func TestUpdateCluster_RejectInvalidParams(t *testing.T) {
testCases := []struct {
name string
@@ -604,3 +617,152 @@ func TestListCluster(t *testing.T) {
})
}
}
func TestGetClusterAndVerifyAccess(t *testing.T) {
t.Run("GetClusterAndVerifyAccess - No Cluster", func(t *testing.T) {
db := &dbmocks.ArgoDB{}
mockCluster := v1alpha1.Cluster{
Name: "test/ing",
Server: "https://127.0.0.1",
Namespaces: []string{"default", "kube-system"},
}
mockClusterList := v1alpha1.ClusterList{
ListMeta: v1.ListMeta{},
Items: []v1alpha1.Cluster{
mockCluster,
},
}
db.On("ListClusters", mock.Anything).Return(&mockClusterList, nil)
server := NewServer(db, newNoopEnforcer(), newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
cluster, err := server.getClusterAndVerifyAccess(context.Background(), &clusterapi.ClusterQuery{
Name: "test/not-exists",
}, rbacpolicy.ActionGet)
assert.Nil(t, cluster)
assert.ErrorIs(t, err, common.PermissionDeniedAPIError)
})
t.Run("GetClusterAndVerifyAccess - Permissions Denied", func(t *testing.T) {
db := &dbmocks.ArgoDB{}
mockCluster := v1alpha1.Cluster{
Name: "test/ing",
Server: "https://127.0.0.1",
Namespaces: []string{"default", "kube-system"},
}
mockClusterList := v1alpha1.ClusterList{
ListMeta: v1.ListMeta{},
Items: []v1alpha1.Cluster{
mockCluster,
},
}
db.On("ListClusters", mock.Anything).Return(&mockClusterList, nil)
server := NewServer(db, newEnforcer(), newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
cluster, err := server.getClusterAndVerifyAccess(context.Background(), &clusterapi.ClusterQuery{
Name: "test/ing",
}, rbacpolicy.ActionGet)
assert.Nil(t, cluster)
assert.ErrorIs(t, err, common.PermissionDeniedAPIError)
})
}
func TestNoClusterEnumeration(t *testing.T) {
db := &dbmocks.ArgoDB{}
mockCluster := v1alpha1.Cluster{
Name: "test/ing",
Server: "https://127.0.0.1",
Namespaces: []string{"default", "kube-system"},
}
mockClusterList := v1alpha1.ClusterList{
ListMeta: v1.ListMeta{},
Items: []v1alpha1.Cluster{
mockCluster,
},
}
db.On("ListClusters", mock.Anything).Return(&mockClusterList, nil)
db.On("GetCluster", mock.Anything, mock.Anything).Return(&mockCluster, nil)
server := NewServer(db, newEnforcer(), newServerInMemoryCache(), &kubetest.MockKubectlCmd{})
t.Run("Get", func(t *testing.T) {
_, err := server.Get(context.Background(), &clusterapi.ClusterQuery{
Name: "cluster-not-exists",
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
_, err = server.Get(context.Background(), &clusterapi.ClusterQuery{
Name: "test/ing",
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
})
t.Run("Update", func(t *testing.T) {
_, err := server.Update(context.Background(), &clusterapi.ClusterUpdateRequest{
Cluster: &v1alpha1.Cluster{
Name: "cluster-not-exists",
},
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
_, err = server.Update(context.Background(), &clusterapi.ClusterUpdateRequest{
Cluster: &v1alpha1.Cluster{
Name: "test/ing",
},
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
})
t.Run("Delete", func(t *testing.T) {
_, err := server.Delete(context.Background(), &clusterapi.ClusterQuery{
Server: "https://127.0.0.2",
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
_, err = server.Delete(context.Background(), &clusterapi.ClusterQuery{
Server: "https://127.0.0.1",
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
})
t.Run("RotateAuth", func(t *testing.T) {
_, err := server.RotateAuth(context.Background(), &clusterapi.ClusterQuery{
Server: "https://127.0.0.2",
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
_, err = server.RotateAuth(context.Background(), &clusterapi.ClusterQuery{
Server: "https://127.0.0.1",
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
})
t.Run("InvalidateCache", func(t *testing.T) {
_, err := server.InvalidateCache(context.Background(), &clusterapi.ClusterQuery{
Server: "https://127.0.0.2",
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
_, err = server.InvalidateCache(context.Background(), &clusterapi.ClusterQuery{
Server: "https://127.0.0.1",
})
assert.Error(t, err)
assert.Equal(t, common.PermissionDeniedAPIError.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about cluster existence")
})
}

View File

@@ -307,12 +307,20 @@ func (s *Server) GetDetailedProject(ctx context.Context, q *project.ProjectQuery
}
proj.NormalizeJWTTokens()
globalProjects := argo.GetGlobalProjects(proj, listersv1alpha1.NewAppProjectLister(s.projInformer.GetIndexer()), s.settingsMgr)
var apiRepos []*v1alpha1.Repository
for _, repo := range repositories {
apiRepos = append(apiRepos, repo.Normalize().Sanitized())
}
var apiClusters []*v1alpha1.Cluster
for _, cluster := range clusters {
apiClusters = append(apiClusters, cluster.Sanitized())
}
return &project.DetailedProjectsResponse{
GlobalProjects: globalProjects,
Project: proj,
Repositories: repositories,
Clusters: clusters,
Repositories: apiRepos,
Clusters: apiClusters,
}, err
}

View File

@@ -219,7 +219,7 @@ func TestRepositoryServer(t *testing.T) {
testRepo := &appsv1.Repository{
Repo: url,
Type: "git",
Username: "foo",
Username: "",
InheritedCreds: true,
}
db.On("GetRepository", context.TODO(), url).Return(testRepo, nil)

View File

@@ -757,7 +757,7 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre
// 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
sOpts = append(sOpts, grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
otelgrpc.StreamServerInterceptor(),
otelgrpc.StreamServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
grpc_logrus.StreamServerInterceptor(a.log),
grpc_prometheus.StreamServerInterceptor,
grpc_auth.StreamServerInterceptor(a.Authenticate),
@@ -771,7 +771,7 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre
)))
sOpts = append(sOpts, grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
bug21955WorkaroundInterceptor,
otelgrpc.UnaryServerInterceptor(),
otelgrpc.UnaryServerInterceptor(), //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
grpc_logrus.UnaryServerInterceptor(a.log),
grpc_prometheus.UnaryServerInterceptor,
grpc_auth.UnaryServerInterceptor(a.Authenticate),
@@ -1034,7 +1034,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
// Webhook handler for git events (Note: cache timeouts are hardcoded because API server does not write to cache and not really using them)
argoDB := db.NewDB(a.Namespace, a.settingsMgr, a.KubeClientset)
acdWebhookHandler := webhook.NewHandler(a.Namespace, a.ArgoCDServerOpts.ApplicationNamespaces, a.AppClientset, a.settings, a.settingsMgr, repocache.NewCache(a.Cache.GetCache(), 24*time.Hour, 3*time.Minute), a.Cache, argoDB)
acdWebhookHandler := webhook.NewHandler(a.Namespace, a.ArgoCDServerOpts.ApplicationNamespaces, a.AppClientset, a.settings, a.settingsMgr, repocache.NewCache(a.Cache.GetCache(), 24*time.Hour, 3*time.Minute), a.Cache, argoDB, a.settingsMgr.GetMaxWebhookPayloadSize())
mux.HandleFunc("/api/webhook", acdWebhookHandler.Handler)

View File

@@ -109,7 +109,6 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
UserLoginsDisabled: userLoginsDisabled,
KustomizeVersions: kustomizeVersions,
UiCssURL: argoCDSettings.UiCssURL,
PasswordPattern: argoCDSettings.PasswordPattern,
TrackingMethod: trackingMethod,
ExecEnabled: argoCDSettings.ExecEnabled,
AppsInAnyNamespaceEnabled: s.appsInAnyNamespaceEnabled,
@@ -122,6 +121,9 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
set.UiBannerPosition = argoCDSettings.UiBannerPosition
set.ControllerNamespace = s.mgr.GetNamespace()
}
if sessionmgr.LoggedIn(ctx) {
set.PasswordPattern = argoCDSettings.PasswordPattern
}
if argoCDSettings.DexConfig != "" {
var cfg settingspkg.DexConfig
err = yaml.Unmarshal([]byte(argoCDSettings.DexConfig), &cfg)

View File

@@ -8,7 +8,7 @@ RUN ln -s /usr/lib/$(uname -m)-linux-gnu /usr/lib/linux-gnu
# Please make sure to also check the contained yarn version and update the references below when upgrading this image's version
FROM docker.io/library/node:20.7.0@sha256:f08c20b9f9c55dd47b1841793f0ee480c5395aa165cd02edfd68b068ed64bfb5 as node
FROM docker.io/library/golang:1.21.3@sha256:02d7116222536a5cf0fcf631f90b507758b669648e0f20186d2dc94a9b419a9b as golang
FROM docker.io/library/golang:1.21.10@sha256:16438a8e66c0c984f732e815ee5b7d715b8e33e81bac6d6a3750b1067744e7ca as golang
FROM docker.io/library/registry:2.8@sha256:41f413c22d6156587e2a51f3e80c09808b8c70e82be149b82b5e0196a88d49b4 as registry

View File

@@ -91,7 +91,7 @@ func TestClusterAddPermissionDenied(t *testing.T) {
Create().
Then().
AndCLIOutput(func(output string, err error) {
assert.True(t, strings.Contains(err.Error(), "PermissionDenied desc = permission denied: clusters, create"))
assert.Contains(t, err.Error(), "PermissionDenied desc = permission denied")
})
}
@@ -256,7 +256,7 @@ func TestClusterDeleteDenied(t *testing.T) {
DeleteByName().
Then().
AndCLIOutput(func(output string, err error) {
assert.True(t, strings.Contains(err.Error(), "PermissionDenied desc = permission denied: clusters, delete"))
assert.Contains(t, err.Error(), "PermissionDenied desc = permission denied")
})
// Attempt to remove cluster creds by server
@@ -270,7 +270,7 @@ func TestClusterDeleteDenied(t *testing.T) {
DeleteByServer().
Then().
AndCLIOutput(func(output string, err error) {
assert.True(t, strings.Contains(err.Error(), "PermissionDenied desc = permission denied: clusters, delete"))
assert.Contains(t, err.Error(), "PermissionDenied desc = permission denied")
})
}

View File

@@ -62,7 +62,8 @@
"@types/react": "^16.9.3",
"@types/react-dom": "^16.8.2",
"normalize-url": "4.3.0",
"rxjs": "6.6.7"
"rxjs": "6.6.7",
"express": "4.21.0"
},
"devDependencies": {
"@babel/core": "^7.7.2",
@@ -117,7 +118,7 @@
"tslint-plugin-prettier": "^2.0.1",
"tslint-react": "^5.0.0",
"typescript": "^4.9.5",
"webpack": "^5.84.1",
"webpack": "^5.94.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.7.4",
"yarn": "^1.22.10"

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
log "github.com/sirupsen/logrus"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
@@ -28,12 +29,15 @@ func Normalize(live, config *unstructured.Unstructured, trustedManagers []string
liveCopy := live.DeepCopy()
configCopy := config.DeepCopy()
normalized := false
results, err := newTypedResults(liveCopy, configCopy, pt)
// error might happen if the resources are not parsable and so cannot be normalized
if err != nil {
return nil, nil, fmt.Errorf("error building typed results: %s", err)
log.Debugf("error building typed results: %v", err)
return liveCopy, configCopy, nil
}
normalized := false
for _, mf := range live.GetManagedFields() {
if trustedManager(mf.Manager, trustedManagers) {
err := normalize(mf, results)

View File

@@ -143,6 +143,16 @@ func TestNormalize(t *testing.T) {
assert.Equal(t, 1, len(vwcConfig.Webhooks))
assert.Equal(t, "", string(vwcConfig.Webhooks[0].ClientConfig.CABundle))
})
t.Run("does not fail if object fails validation schema", func(t *testing.T) {
desiredState := StrToUnstructured(testdata.DesiredDeploymentYaml)
require.NoError(t, unstructured.SetNestedField(desiredState.Object, "spec", "hello", "world"))
liveState := StrToUnstructured(testdata.LiveDeploymentWithManagedReplicaYaml)
pt := parser.Type("io.k8s.api.apps.v1.Deployment")
_, _, err := managedfields.Normalize(liveState, desiredState, []string{}, &pt)
require.NoError(t, err)
})
}
func validateNestedFloat64(t *testing.T, expected float64, obj *unstructured.Unstructured, fields ...string) {

View File

@@ -17,8 +17,8 @@ var (
// see https://github.com/open-telemetry/opentelemetry-go-contrib/issues/4226 for details
func ensureInitialized() {
interceptorsInitialized.Do(func() {
otelUnaryInterceptor = otelgrpc.UnaryClientInterceptor()
otelStreamInterceptor = otelgrpc.StreamClientInterceptor()
otelUnaryInterceptor = otelgrpc.UnaryClientInterceptor() //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
otelStreamInterceptor = otelgrpc.StreamClientInterceptor() //nolint:staticcheck // TODO: ignore SA1019 for depreciation: see https://github.com/argoproj/argo-cd/issues/18258
})
}

View File

@@ -429,6 +429,8 @@ const (
settingsWebhookAzureDevOpsUsernameKey = "webhook.azuredevops.username"
// settingsWebhookAzureDevOpsPasswordKey is the key for Azure DevOps webhook password
settingsWebhookAzureDevOpsPasswordKey = "webhook.azuredevops.password"
// settingsWebhookMaxPayloadSize is the key for the maximum payload size for webhooks in MB
settingsWebhookMaxPayloadSizeMB = "webhook.maxPayloadSizeMB"
// settingsApplicationInstanceLabelKey is the key to configure injected app instance label key
settingsApplicationInstanceLabelKey = "application.instanceLabelKey"
// settingsResourceTrackingMethodKey is the key to configure tracking method for application resources
@@ -506,14 +508,17 @@ const (
RespectRBACValueNormal = "normal"
)
var (
sourceTypeToEnableGenerationKey = map[v1alpha1.ApplicationSourceType]string{
v1alpha1.ApplicationSourceTypeKustomize: "kustomize.enable",
v1alpha1.ApplicationSourceTypeHelm: "helm.enable",
v1alpha1.ApplicationSourceTypeDirectory: "jsonnet.enable",
}
const (
// default max webhook payload size is 1GB
defaultMaxWebhookPayloadSize = int64(1) * 1024 * 1024 * 1024
)
var sourceTypeToEnableGenerationKey = map[v1alpha1.ApplicationSourceType]string{
v1alpha1.ApplicationSourceTypeKustomize: "kustomize.enable",
v1alpha1.ApplicationSourceTypeHelm: "helm.enable",
v1alpha1.ApplicationSourceTypeDirectory: "jsonnet.enable",
}
// SettingsManager holds config info for a new manager with which to access Kubernetes ConfigMaps.
type SettingsManager struct {
ctx context.Context
@@ -2209,3 +2214,22 @@ func (mgr *SettingsManager) GetResourceCustomLabels() ([]string, error) {
}
return []string{}, nil
}
func (mgr *SettingsManager) GetMaxWebhookPayloadSize() int64 {
argoCDCM, err := mgr.getConfigMap()
if err != nil {
return defaultMaxWebhookPayloadSize
}
if argoCDCM.Data[settingsWebhookMaxPayloadSizeMB] == "" {
return defaultMaxWebhookPayloadSize
}
maxPayloadSizeMB, err := strconv.ParseInt(argoCDCM.Data[settingsWebhookMaxPayloadSizeMB], 10, 64)
if err != nil {
log.Warnf("Failed to parse '%s' key: %v", settingsWebhookMaxPayloadSizeMB, err)
return defaultMaxWebhookPayloadSize
}
return maxPayloadSizeMB * 1024 * 1024
}

View File

@@ -42,6 +42,8 @@ type settingsSource interface {
// https://github.com/shadow-maint/shadow/blob/master/libmisc/chkname.c#L36
const usernameRegex = `[a-zA-Z0-9_\.][a-zA-Z0-9_\.-]{0,30}[a-zA-Z0-9_\.\$-]?`
const payloadQueueSize = 50000
var (
_ settingsSource = &settings.SettingsManager{}
errBasicAuthVerificationFailed = errors.New("basic auth verification failed")
@@ -62,9 +64,11 @@ type ArgoCDWebhookHandler struct {
azuredevopsAuthHandler func(r *http.Request) error
gogs *gogs.Webhook
settingsSrc settingsSource
queue chan interface{}
maxWebhookPayloadSizeB int64
}
func NewHandler(namespace string, applicationNamespaces []string, appClientset appclientset.Interface, set *settings.ArgoCDSettings, settingsSrc settingsSource, repoCache *cache.Cache, serverCache *servercache.Cache, argoDB db.ArgoDB) *ArgoCDWebhookHandler {
func NewHandler(namespace string, applicationNamespaces []string, appClientset appclientset.Interface, set *settings.ArgoCDSettings, settingsSrc settingsSource, repoCache *cache.Cache, serverCache *servercache.Cache, argoDB db.ArgoDB, maxWebhookPayloadSizeB int64) *ArgoCDWebhookHandler {
githubWebhook, err := github.New(github.Options.Secret(set.WebhookGitHubSecret))
if err != nil {
log.Warnf("Unable to init the GitHub webhook")
@@ -114,6 +118,8 @@ func NewHandler(namespace string, applicationNamespaces []string, appClientset a
repoCache: repoCache,
serverCache: serverCache,
db: argoDB,
queue: make(chan interface{}, payloadQueueSize),
maxWebhookPayloadSizeB: maxWebhookPayloadSizeB,
}
return &acdWebhook
@@ -458,6 +464,8 @@ func (a *ArgoCDWebhookHandler) Handler(w http.ResponseWriter, r *http.Request) {
var payload interface{}
var err error
r.Body = http.MaxBytesReader(w, r.Body, a.maxWebhookPayloadSizeB)
switch {
case r.Header.Get("X-Vss-Activityid") != "":
if err = a.azuredevopsAuthHandler(r); err != nil {
@@ -500,6 +508,14 @@ func (a *ArgoCDWebhookHandler) Handler(w http.ResponseWriter, r *http.Request) {
}
if err != nil {
// If the error is due to a large payload, return a more user-friendly error message
if err.Error() == "error parsing payload" {
msg := fmt.Sprintf("Webhook processing failed: The payload is either too large or corrupted. Please check the payload size (must be under %v MB) and ensure it is valid JSON", a.maxWebhookPayloadSizeB/1024/1024)
log.WithField(common.SecurityField, common.SecurityHigh).Warn(msg)
http.Error(w, msg, http.StatusBadRequest)
return
}
log.Infof("Webhook processing failed: %s", err)
status := http.StatusBadRequest
if r.Method != http.MethodPost {

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/stretchr/testify/require"
"io"
"net/http"
"net/http/httptest"
@@ -56,6 +57,11 @@ type reactorDef struct {
}
func NewMockHandler(reactor *reactorDef, applicationNamespaces []string, objects ...runtime.Object) *ArgoCDWebhookHandler {
defaultMaxPayloadSize := int64(1) * 1024 * 1024 * 1024
return NewMockHandlerWithPayloadLimit(reactor, applicationNamespaces, defaultMaxPayloadSize, objects...)
}
func NewMockHandlerWithPayloadLimit(reactor *reactorDef, applicationNamespaces []string, maxPayloadSize int64, objects ...runtime.Object) *ArgoCDWebhookHandler {
appClientset := appclientset.NewSimpleClientset(objects...)
if reactor != nil {
defaultReactor := appClientset.ReactionChain[0]
@@ -71,7 +77,7 @@ func NewMockHandler(reactor *reactorDef, applicationNamespaces []string, objects
cacheClient,
1*time.Minute,
1*time.Minute,
), servercache.NewCache(appstate.NewCache(cacheClient, time.Minute), time.Minute, time.Minute, time.Minute), &mocks.ArgoDB{})
), servercache.NewCache(appstate.NewCache(cacheClient, time.Minute), time.Minute, time.Minute, time.Minute), &mocks.ArgoDB{}, maxPayloadSize)
}
func TestGitHubCommitEvent(t *testing.T) {
@@ -391,8 +397,9 @@ func TestInvalidEvent(t *testing.T) {
req.Header.Set("X-GitHub-Event", "push")
w := httptest.NewRecorder()
h.Handler(w, req)
assert.Equal(t, w.Code, http.StatusBadRequest)
expectedLogResult := "Webhook processing failed: error parsing payload"
close(h.queue)
assert.Equal(t, http.StatusBadRequest, w.Code)
expectedLogResult := "Webhook processing failed: The payload is either too large or corrupted. Please check the payload size (must be under 1024 MB) and ensure it is valid JSON"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assert.Equal(t, expectedLogResult+"\n", w.Body.String())
hook.Reset()
@@ -683,3 +690,21 @@ func Test_getWebUrlRegex(t *testing.T) {
})
}
}
func TestGitHubCommitEventMaxPayloadSize(t *testing.T) {
hook := test.NewGlobal()
maxPayloadSize := int64(100)
h := NewMockHandlerWithPayloadLimit(nil, []string{}, maxPayloadSize)
req := httptest.NewRequest(http.MethodPost, "/api/webhook", nil)
req.Header.Set("X-GitHub-Event", "push")
eventJSON, err := os.ReadFile("testdata/github-commit-event.json")
require.NoError(t, err)
req.Body = io.NopCloser(bytes.NewReader(eventJSON))
w := httptest.NewRecorder()
h.Handler(w, req)
close(h.queue)
assert.Equal(t, http.StatusBadRequest, w.Code)
expectedLogResult := "Webhook processing failed: The payload is either too large or corrupted. Please check the payload size (must be under 0 MB) and ensure it is valid JSON"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
hook.Reset()
}