Compare commits

...

22 Commits

Author SHA1 Message Date
Michael Crenshaw
19b19fda8d docs: Add step to update 'stable' tag after release
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-11-04 09:56:13 -05:00
dependabot[bot]
b7691b2167 chore(deps): bump renovatebot/github-action from 43.0.19 to 43.0.20 (#25156)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-04 02:54:20 -10:00
Peter Jiang
21ae489589 fix: return empty instead of error if cache unavailable (#25072)
Signed-off-by: Peter Jiang <peterjiang823@gmail.com>
Signed-off-by: Peter Jiang <35584807+pjiang-dev@users.noreply.github.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2025-11-04 17:56:19 +05:30
Rick Brouwer
e58bdf2f87 feat: implement KEDA scaledJob health-checks (#25106)
Signed-off-by: Rick Brouwer <rickbrouwer@gmail.com>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2025-11-03 19:13:30 -05:00
Alexander Matyushentsev
7a09f69ad6 fix: avoid calling UpdateRevisionForPaths unnecessary (#25151)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2025-11-03 21:48:14 +00:00
Alexander Matyushentsev
1b08fd1004 feat: add ability to use shallow clone for repositories (#24931)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2025-11-03 13:00:59 -08:00
Revital Barletz
0a93e5701f docs: Update Kustomize documentation for forceCommonLabels and forceCommonAnnotations (#25138)
Signed-off-by: Revital Barletz <Revital.barletz@octopus.com>
2025-11-03 15:14:01 -05:00
argoproj-renovate[bot]
5072fb7136 chore(deps): update dependency markdown to v3.10 (#25152)
Signed-off-by: renovate[bot] <renovate[bot]@users.noreply.github.com>
Co-authored-by: argoproj-renovate[bot] <161757507+argoproj-renovate[bot]@users.noreply.github.com>
2025-11-03 15:13:04 -05:00
dependabot[bot]
b91c191a34 chore(deps): bump github.com/casbin/casbin/v2 from 2.128.0 to 2.131.0 (#25142)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-03 10:05:05 -05:00
github-actions[bot]
fe727c8fc9 [Bot] docs: Update Snyk report (#25135)
Signed-off-by: CI <ci@argoproj.com>
Co-authored-by: CI <ci@argoproj.com>
2025-11-03 14:29:08 +00:00
dudinea
fe4ab01cba fix: capture stderr in executil RunWithExecRunOpts (#25139)
Signed-off-by: Eugene Doudine <eugene.doudine@octopus.com>
2025-11-02 17:01:38 +02:00
Matthieu MOREL
4ea276860c chore: refactor test functions to pass context from testing.T to fixtures (#25134)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-11-02 13:39:24 +01:00
Matthieu MOREL
f26533ab37 chore: use Expecter Structs from mockery (#25133)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-11-01 13:07:08 +00:00
Atif Ali
c2f611f8cd fix(ui): Improve Delete Dialog Behaviour when deleting child apps in the app-of-app pattern (#24802)
Signed-off-by: Atif Ali <atali@redhat.com>
2025-10-30 14:42:16 -04:00
dependabot[bot]
ef48aa9c37 chore(deps): bump library/busybox from 2f590fc to e3652a0 in /test/e2e/multiarch-container (#25116)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-30 10:50:23 -04:00
dependabot[bot]
1b4fde1986 chore(deps): bump gitlab.com/gitlab-org/api/client-go from 0.157.0 to 0.157.1 (#25108)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-30 02:52:52 +00:00
Simon Dahlbacka
ca84c31a46 docs: clarify resource.exclusions 25009 (#25107)
Signed-off-by: Simon Dahlbacka <simon.dahlbacka@fellowmind.fi>
2025-10-29 20:56:33 -04:00
Afzal Ansari
f5eaae73a2 docs: add app password step to retrieve using gmail support (#22706)
Signed-off-by: Afzal Ansari <afzal442@gmail.com>
2025-10-29 16:03:34 +00:00
jwinters01
a2f57be3d5 docs: application view ui extension docs (#25050)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Signed-off-by: Jonathan Winters <wintersjonathan0@gmail.com>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2025-10-28 14:05:58 -04:00
Josh Soref
0d0cec6b66 fix: Only show apiVersion/kind when targetState is defined (#25068)
Signed-off-by: Josh Soref <jsoref@gmail.com>
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
Co-authored-by: Yusuke Abe <chansuke0@gmail.com>
2025-10-28 09:42:40 +01:00
Afzal Ansari
7ba62f9838 docs: add overrides in multi-source applications (#25089)
Signed-off-by: Afzal Ansari <afzal442@gmail.com>
2025-10-28 13:33:52 +05:30
dependabot[bot]
e80395bacf chore(deps): bump renovatebot/github-action from 43.0.18 to 43.0.19 (#25099)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-28 08:30:38 +01:00
131 changed files with 5042 additions and 3816 deletions

View File

@@ -22,5 +22,6 @@ Target GA date: ___. __, ____
- [ ] At release date, evaluate if any bugs justify delaying the release. If not, cut the release (or delegate this task to an Approver and coordinate timing)
- [ ] If unreleased changes are on the release branch for {current minor version minus 3}, cut a final patch release for that series (or delegate this task to an Approver and coordinate timing)
- [ ] After the release, post in #argo-cd that the {current minor version minus 3} has reached EOL (example: https://cloud-native.slack.com/archives/C01TSERG0KZ/p1667336234059729)
- [ ] Update the `stable` tag to be the GA release you just pushed
- [ ] (For the next release champion) Review the [items scheduled for the next release](https://github.com/orgs/argoproj/projects/25). If any item does not have an assignee who can commit to finish the feature, move it to the next release.
- [ ] (For the next release champion) Schedule a time mid-way through the release cycle to review items again.
- [ ] (For the next release champion) Schedule a time mid-way through the release cycle to review items again.

View File

@@ -30,7 +30,7 @@ jobs:
go-version: 1.25.3
- name: Self-hosted Renovate
uses: renovatebot/github-action@aec779d4f7845f8431ddf403cf9659d4702ddde0 #43.0.18
uses: renovatebot/github-action@ea850436a5fe75c0925d583c7a02c60a5865461d #43.0.20
with:
configurationFile: .github/configs/renovate-config.js
token: '${{ steps.get_token.outputs.token }}'

View File

@@ -1,11 +1,5 @@
dir: '{{.InterfaceDir}}/mocks'
structname: '{{.InterfaceName}}'
filename: '{{.InterfaceName}}.go'
pkgname: mocks
template-data:
unroll-variadic: true
packages:
github.com/argoproj/argo-cd/v3/applicationset/generators:
interfaces:
@@ -14,11 +8,10 @@ packages:
interfaces:
Repos: {}
github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider:
config:
dir: applicationset/services/scm_provider/aws_codecommit/mocks
interfaces:
AWSCodeCommitClient: {}
AWSTaggingClient: {}
AzureDevOpsClientFactory: {}
github.com/argoproj/argo-cd/v3/applicationset/utils:
interfaces:
Renderer: {}
@@ -47,8 +40,8 @@ packages:
AppProjectInterface: {}
github.com/argoproj/argo-cd/v3/reposerver/apiclient:
interfaces:
RepoServerService_GenerateManifestWithFilesClient: {}
RepoServerServiceClient: {}
RepoServerService_GenerateManifestWithFilesClient: {}
github.com/argoproj/argo-cd/v3/server/application:
interfaces:
Broadcaster: {}
@@ -63,26 +56,37 @@ packages:
github.com/argoproj/argo-cd/v3/util/db:
interfaces:
ArgoDB: {}
RepoCredsDB: {}
github.com/argoproj/argo-cd/v3/util/git:
interfaces:
Client: {}
github.com/argoproj/argo-cd/v3/util/helm:
interfaces:
Client: {}
github.com/argoproj/argo-cd/v3/util/oci:
interfaces:
Client: {}
github.com/argoproj/argo-cd/v3/util/io:
interfaces:
TempPaths: {}
github.com/argoproj/argo-cd/v3/util/notification/argocd:
interfaces:
Service: {}
github.com/argoproj/argo-cd/v3/util/oci:
interfaces:
Client: {}
github.com/argoproj/argo-cd/v3/util/workloadidentity:
interfaces:
TokenProvider: {}
github.com/argoproj/gitops-engine/pkg/cache:
interfaces:
ClusterCache: {}
github.com/argoproj/gitops-engine/pkg/diff:
interfaces:
ServerSideDryRunner: {}
github.com/microsoft/azure-devops-go-api/azuredevops/v7/git:
config:
dir: applicationset/services/scm_provider/azure_devops/git/mocks
interfaces:
Client: {}
pkgname: mocks
structname: '{{.InterfaceName}}'
template-data:
unroll-variadic: true

View File

@@ -1832,16 +1832,16 @@ func TestGetMinRequeueAfter(t *testing.T) {
Clusters: &v1alpha1.ClusterGenerator{},
}
generatorMock0 := mocks.Generator{}
generatorMock0.On("GetRequeueAfter", &generator).
generatorMock0 := &mocks.Generator{}
generatorMock0.EXPECT().GetRequeueAfter(&generator).
Return(generators.NoRequeueAfter)
generatorMock1 := mocks.Generator{}
generatorMock1.On("GetRequeueAfter", &generator).
generatorMock1 := &mocks.Generator{}
generatorMock1.EXPECT().GetRequeueAfter(&generator).
Return(time.Duration(1) * time.Second)
generatorMock10 := mocks.Generator{}
generatorMock10.On("GetRequeueAfter", &generator).
generatorMock10 := &mocks.Generator{}
generatorMock10.EXPECT().GetRequeueAfter(&generator).
Return(time.Duration(10) * time.Second)
r := ApplicationSetReconciler{
@@ -1850,9 +1850,9 @@ func TestGetMinRequeueAfter(t *testing.T) {
Recorder: record.NewFakeRecorder(0),
Metrics: metrics,
Generators: map[string]generators.Generator{
"List": &generatorMock10,
"Git": &generatorMock1,
"Clusters": &generatorMock1,
"List": generatorMock10,
"Git": generatorMock1,
"Clusters": generatorMock1,
},
}
@@ -1889,10 +1889,10 @@ func TestRequeueGeneratorFails(t *testing.T) {
PullRequest: &v1alpha1.PullRequestGenerator{},
}
generatorMock := mocks.Generator{}
generatorMock.On("GetTemplate", &generator).
generatorMock := &mocks.Generator{}
generatorMock.EXPECT().GetTemplate(&generator).
Return(&v1alpha1.ApplicationSetTemplate{})
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
generatorMock.EXPECT().GenerateParams(&generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
Return([]map[string]any{}, errors.New("Simulated error generating params that could be related to an external service/API call"))
metrics := appsetmetrics.NewFakeAppsetMetrics()
@@ -1902,7 +1902,7 @@ func TestRequeueGeneratorFails(t *testing.T) {
Scheme: scheme,
Recorder: record.NewFakeRecorder(0),
Generators: map[string]generators.Generator{
"PullRequest": &generatorMock,
"PullRequest": generatorMock,
},
Metrics: metrics,
}

View File

@@ -86,28 +86,28 @@ func TestGenerateApplications(t *testing.T) {
}
t.Run(cc.name, func(t *testing.T) {
generatorMock := genmock.Generator{}
generatorMock := &genmock.Generator{}
generator := v1alpha1.ApplicationSetGenerator{
List: &v1alpha1.ListGenerator{},
}
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
generatorMock.EXPECT().GenerateParams(&generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
Return(cc.params, cc.generateParamsError)
generatorMock.On("GetTemplate", &generator).
generatorMock.EXPECT().GetTemplate(&generator).
Return(&v1alpha1.ApplicationSetTemplate{})
rendererMock := rendmock.Renderer{}
rendererMock := &rendmock.Renderer{}
var expectedApps []v1alpha1.Application
if cc.generateParamsError == nil {
for _, p := range cc.params {
if cc.rendererError != nil {
rendererMock.On("RenderTemplateParams", GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
rendererMock.EXPECT().RenderTemplateParams(GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
Return(nil, cc.rendererError)
} else {
rendererMock.On("RenderTemplateParams", GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
rendererMock.EXPECT().RenderTemplateParams(GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
Return(&app, nil)
expectedApps = append(expectedApps, app)
}
@@ -115,9 +115,9 @@ func TestGenerateApplications(t *testing.T) {
}
generators := map[string]generators.Generator{
"List": &generatorMock,
"List": generatorMock,
}
renderer := &rendererMock
renderer := rendererMock
got, reason, err := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
@@ -200,26 +200,26 @@ func TestMergeTemplateApplications(t *testing.T) {
cc := c
t.Run(cc.name, func(t *testing.T) {
generatorMock := genmock.Generator{}
generatorMock := &genmock.Generator{}
generator := v1alpha1.ApplicationSetGenerator{
List: &v1alpha1.ListGenerator{},
}
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
generatorMock.EXPECT().GenerateParams(&generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
Return(cc.params, nil)
generatorMock.On("GetTemplate", &generator).
generatorMock.EXPECT().GetTemplate(&generator).
Return(&cc.overrideTemplate)
rendererMock := rendmock.Renderer{}
rendererMock := &rendmock.Renderer{}
rendererMock.On("RenderTemplateParams", GetTempApplication(cc.expectedMerged), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), cc.params[0], false, []string(nil)).
rendererMock.EXPECT().RenderTemplateParams(GetTempApplication(cc.expectedMerged), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), cc.params[0], false, []string(nil)).
Return(&cc.expectedApps[0], nil)
generators := map[string]generators.Generator{
"List": &generatorMock,
"List": generatorMock,
}
renderer := &rendererMock
renderer := rendererMock
got, _, _ := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
@@ -312,19 +312,19 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) {
},
} {
t.Run(cases.name, func(t *testing.T) {
generatorMock := genmock.Generator{}
generatorMock := &genmock.Generator{}
generator := v1alpha1.ApplicationSetGenerator{
PullRequest: &v1alpha1.PullRequestGenerator{},
}
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
generatorMock.EXPECT().GenerateParams(&generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
Return(cases.params, nil)
generatorMock.On("GetTemplate", &generator).
Return(&cases.template, nil)
generatorMock.EXPECT().GetTemplate(&generator).
Return(&cases.template)
generators := map[string]generators.Generator{
"PullRequest": &generatorMock,
"PullRequest": generatorMock,
}
renderer := &utils.Render{}

View File

@@ -223,7 +223,7 @@ func TestTransForm(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
testGenerators := map[string]Generator{
"Clusters": getMockClusterGenerator(),
"Clusters": getMockClusterGenerator(t.Context()),
}
applicationSetInfo := argov1alpha1.ApplicationSet{
@@ -260,7 +260,7 @@ func emptyTemplate() argov1alpha1.ApplicationSetTemplate {
}
}
func getMockClusterGenerator() Generator {
func getMockClusterGenerator(ctx context.Context) Generator {
clusters := []crtclient.Object{
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
@@ -342,19 +342,19 @@ func getMockClusterGenerator() Generator {
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
return NewClusterGenerator(context.Background(), fakeClient, appClientset, "namespace")
return NewClusterGenerator(ctx, fakeClient, appClientset, "namespace")
}
func getMockGitGenerator() Generator {
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil)
gitGenerator := NewGitGenerator(&argoCDServiceMock, "namespace")
argoCDServiceMock := &mocks.Repos{}
argoCDServiceMock.EXPECT().GetDirectories(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil)
gitGenerator := NewGitGenerator(argoCDServiceMock, "namespace")
return gitGenerator
}
func TestGetRelevantGenerators(t *testing.T) {
testGenerators := map[string]Generator{
"Clusters": getMockClusterGenerator(),
"Clusters": getMockClusterGenerator(t.Context()),
"Git": getMockGitGenerator(),
}

View File

@@ -320,11 +320,11 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock := mocks.NewRepos(t)
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
argoCDServiceMock.EXPECT().GetDirectories(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
gitGenerator := NewGitGenerator(argoCDServiceMock, "")
applicationSetInfo := v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -357,8 +357,6 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, testCaseCopy.expected, got)
}
argoCDServiceMock.AssertExpectations(t)
})
}
}
@@ -623,11 +621,11 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock := mocks.NewRepos(t)
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
argoCDServiceMock.EXPECT().GetDirectories(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
gitGenerator := NewGitGenerator(argoCDServiceMock, "")
applicationSetInfo := v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -660,8 +658,6 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, testCaseCopy.expected, got)
}
argoCDServiceMock.AssertExpectations(t)
})
}
}
@@ -1000,11 +996,11 @@ cluster:
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
argoCDServiceMock := mocks.NewRepos(t)
argoCDServiceMock.EXPECT().GetFiles(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
gitGenerator := NewGitGenerator(argoCDServiceMock, "")
applicationSetInfo := v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -1036,8 +1032,6 @@ cluster:
require.NoError(t, err)
assert.ElementsMatch(t, testCaseCopy.expected, got)
}
argoCDServiceMock.AssertExpectations(t)
})
}
}
@@ -1331,7 +1325,7 @@ env: testing
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock := mocks.NewRepos(t)
// IMPORTANT: we try to get the files from the repo server that matches the patterns
// If we find those files also satisfy the exclude pattern, we remove them from map
@@ -1339,18 +1333,16 @@ env: testing
// With the below mock setup, we make sure that if the GetFiles() function gets called
// for a include or exclude pattern, it should always return the includeFiles or excludeFiles.
for _, pattern := range testCaseCopy.excludePattern {
argoCDServiceMock.
On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
argoCDServiceMock.EXPECT().GetFiles(mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
Return(testCaseCopy.excludeFiles, testCaseCopy.repoPathsError)
}
for _, pattern := range testCaseCopy.includePattern {
argoCDServiceMock.
On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
argoCDServiceMock.EXPECT().GetFiles(mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
Return(testCaseCopy.includeFiles, testCaseCopy.repoPathsError)
}
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
gitGenerator := NewGitGenerator(argoCDServiceMock, "")
applicationSetInfo := v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -1382,8 +1374,6 @@ env: testing
require.NoError(t, err)
assert.ElementsMatch(t, testCaseCopy.expected, got)
}
argoCDServiceMock.AssertExpectations(t)
})
}
}
@@ -1672,7 +1662,7 @@ env: testing
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock := mocks.NewRepos(t)
// IMPORTANT: we try to get the files from the repo server that matches the patterns
// If we find those files also satisfy the exclude pattern, we remove them from map
@@ -1680,18 +1670,16 @@ env: testing
// With the below mock setup, we make sure that if the GetFiles() function gets called
// for a include or exclude pattern, it should always return the includeFiles or excludeFiles.
for _, pattern := range testCaseCopy.excludePattern {
argoCDServiceMock.
On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
argoCDServiceMock.EXPECT().GetFiles(mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
Return(testCaseCopy.excludeFiles, testCaseCopy.repoPathsError)
}
for _, pattern := range testCaseCopy.includePattern {
argoCDServiceMock.
On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
argoCDServiceMock.EXPECT().GetFiles(mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
Return(testCaseCopy.includeFiles, testCaseCopy.repoPathsError)
}
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
gitGenerator := NewGitGenerator(argoCDServiceMock, "")
applicationSetInfo := v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -1723,8 +1711,6 @@ env: testing
require.NoError(t, err)
assert.ElementsMatch(t, testCaseCopy.expected, got)
}
argoCDServiceMock.AssertExpectations(t)
})
}
}
@@ -1908,25 +1894,23 @@ func TestGitGeneratorParamsFromFilesWithExcludeOptionGoTemplate(t *testing.T) {
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock := mocks.NewRepos(t)
// IMPORTANT: we try to get the files from the repo server that matches the patterns
// If we find those files also satisfy the exclude pattern, we remove them from map
// This is generally done by the g.repos.GetFiles() function.
// With the below mock setup, we make sure that if the GetFiles() function gets called
// for a include or exclude pattern, it should always return the includeFiles or excludeFiles.
for _, pattern := range testCaseCopy.excludePattern {
argoCDServiceMock.
On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
argoCDServiceMock.EXPECT().GetFiles(mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
Return(testCaseCopy.excludeFiles, testCaseCopy.repoPathsError)
}
for _, pattern := range testCaseCopy.includePattern {
argoCDServiceMock.
On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
argoCDServiceMock.EXPECT().GetFiles(mock.Anything, mock.Anything, mock.Anything, mock.Anything, pattern, mock.Anything, mock.Anything).
Return(testCaseCopy.includeFiles, testCaseCopy.repoPathsError)
}
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
gitGenerator := NewGitGenerator(argoCDServiceMock, "")
applicationSetInfo := v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -1958,8 +1942,6 @@ func TestGitGeneratorParamsFromFilesWithExcludeOptionGoTemplate(t *testing.T) {
require.NoError(t, err)
assert.ElementsMatch(t, testCaseCopy.expected, got)
}
argoCDServiceMock.AssertExpectations(t)
})
}
}
@@ -2279,11 +2261,11 @@ cluster:
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
argoCDServiceMock := mocks.NewRepos(t)
argoCDServiceMock.EXPECT().GetFiles(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
gitGenerator := NewGitGenerator(&argoCDServiceMock, "")
gitGenerator := NewGitGenerator(argoCDServiceMock, "")
applicationSetInfo := v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -2315,8 +2297,6 @@ cluster:
require.NoError(t, err)
assert.ElementsMatch(t, testCaseCopy.expected, got)
}
argoCDServiceMock.AssertExpectations(t)
})
}
}
@@ -2482,7 +2462,7 @@ func TestGitGenerator_GenerateParams(t *testing.T) {
},
}
for _, testCase := range cases {
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock := mocks.NewRepos(t)
if testCase.callGetDirectories {
var project any
@@ -2492,9 +2472,9 @@ func TestGitGenerator_GenerateParams(t *testing.T) {
project = mock.Anything
}
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, project, mock.Anything, mock.Anything).Return(testCase.repoApps, testCase.repoPathsError)
argoCDServiceMock.EXPECT().GetDirectories(mock.Anything, mock.Anything, mock.Anything, project, mock.Anything, mock.Anything).Return(testCase.repoApps, testCase.repoPathsError)
}
gitGenerator := NewGitGenerator(&argoCDServiceMock, "argocd")
gitGenerator := NewGitGenerator(argoCDServiceMock, "argocd")
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
@@ -2510,7 +2490,5 @@ func TestGitGenerator_GenerateParams(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, testCase.expected, got)
}
argoCDServiceMock.AssertExpectations(t)
}
}

View File

@@ -12,12 +12,12 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"github.com/argoproj/argo-cd/v3/applicationset/services/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
generatorsMock "github.com/argoproj/argo-cd/v3/applicationset/generators/mocks"
servicesMocks "github.com/argoproj/argo-cd/v3/applicationset/services/mocks"
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
)
@@ -136,7 +136,7 @@ func TestMatrixGenerate(t *testing.T) {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
genMock := &generatorMock{}
genMock := &generatorsMock.Generator{}
appSet := &v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -149,7 +149,7 @@ func TestMatrixGenerate(t *testing.T) {
Git: g.Git,
List: g.List,
}
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]any{
genMock.EXPECT().GenerateParams(mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]any{
{
"path": "app1",
"path.basename": "app1",
@@ -162,7 +162,7 @@ func TestMatrixGenerate(t *testing.T) {
},
}, nil)
genMock.On("GetTemplate", &gitGeneratorSpec).
genMock.EXPECT().GetTemplate(&gitGeneratorSpec).
Return(&v1alpha1.ApplicationSetTemplate{})
}
@@ -343,7 +343,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
genMock := &generatorMock{}
genMock := &generatorsMock.Generator{}
appSet := &v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -358,7 +358,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
Git: g.Git,
List: g.List,
}
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]any{
genMock.EXPECT().GenerateParams(mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]any{
{
"path": map[string]string{
"path": "app1",
@@ -375,7 +375,7 @@ func TestMatrixGenerateGoTemplate(t *testing.T) {
},
}, nil)
genMock.On("GetTemplate", &gitGeneratorSpec).
genMock.EXPECT().GetTemplate(&gitGeneratorSpec).
Return(&v1alpha1.ApplicationSetTemplate{})
}
@@ -507,7 +507,7 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
mock := &generatorMock{}
mock := &generatorsMock.Generator{}
for _, g := range testCaseCopy.baseGenerators {
gitGeneratorSpec := v1alpha1.ApplicationSetGenerator{
@@ -517,7 +517,7 @@ func TestMatrixGetRequeueAfter(t *testing.T) {
SCMProvider: g.SCMProvider,
ClusterDecisionResource: g.ClusterDecisionResource,
}
mock.On("GetRequeueAfter", &gitGeneratorSpec).Return(testCaseCopy.gitGetRequeueAfter, nil)
mock.EXPECT().GetRequeueAfter(&gitGeneratorSpec).Return(testCaseCopy.gitGetRequeueAfter)
}
matrixGenerator := NewMatrixGenerator(
@@ -634,7 +634,7 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
genMock := &generatorMock{}
genMock := &generatorsMock.Generator{}
appSet := &v1alpha1.ApplicationSet{}
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
@@ -650,7 +650,7 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
Git: g.Git,
Clusters: g.Clusters,
}
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]any{
genMock.EXPECT().GenerateParams(mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]any{
{
"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json",
"path.basename": "dev",
@@ -662,7 +662,7 @@ func TestInterpolatedMatrixGenerate(t *testing.T) {
"path.basenameNormalized": "prod",
},
}, nil)
genMock.On("GetTemplate", &gitGeneratorSpec).
genMock.EXPECT().GetTemplate(&gitGeneratorSpec).
Return(&v1alpha1.ApplicationSetTemplate{})
}
matrixGenerator := NewMatrixGenerator(
@@ -813,7 +813,7 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
genMock := &generatorMock{}
genMock := &generatorsMock.Generator{}
appSet := &v1alpha1.ApplicationSet{
Spec: v1alpha1.ApplicationSetSpec{
GoTemplate: true,
@@ -833,7 +833,7 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
Git: g.Git,
Clusters: g.Clusters,
}
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]any{
genMock.EXPECT().GenerateParams(mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]any{
{
"path": map[string]string{
"path": "examples/git-generator-files-discovery/cluster-config/dev/config.json",
@@ -849,7 +849,7 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) {
},
},
}, nil)
genMock.On("GetTemplate", &gitGeneratorSpec).
genMock.EXPECT().GetTemplate(&gitGeneratorSpec).
Return(&v1alpha1.ApplicationSetTemplate{})
}
matrixGenerator := NewMatrixGenerator(
@@ -969,7 +969,7 @@ func TestMatrixGenerateListElementsYaml(t *testing.T) {
testCaseCopy := testCase // Since tests may run in parallel
t.Run(testCaseCopy.name, func(t *testing.T) {
genMock := &generatorMock{}
genMock := &generatorsMock.Generator{}
appSet := &v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -984,7 +984,7 @@ func TestMatrixGenerateListElementsYaml(t *testing.T) {
Git: g.Git,
List: g.List,
}
genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]any{{
genMock.EXPECT().GenerateParams(mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet, mock.Anything).Return([]map[string]any{{
"foo": map[string]any{
"bar": []any{
map[string]any{
@@ -1009,7 +1009,7 @@ func TestMatrixGenerateListElementsYaml(t *testing.T) {
},
},
}}, nil)
genMock.On("GetTemplate", &gitGeneratorSpec).
genMock.EXPECT().GetTemplate(&gitGeneratorSpec).
Return(&v1alpha1.ApplicationSetTemplate{})
}
@@ -1037,28 +1037,6 @@ func TestMatrixGenerateListElementsYaml(t *testing.T) {
}
}
type generatorMock struct {
mock.Mock
}
func (g *generatorMock) GetTemplate(appSetGenerator *v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate {
args := g.Called(appSetGenerator)
return args.Get(0).(*v1alpha1.ApplicationSetTemplate)
}
func (g *generatorMock) GenerateParams(appSetGenerator *v1alpha1.ApplicationSetGenerator, appSet *v1alpha1.ApplicationSet, _ client.Client) ([]map[string]any, error) {
args := g.Called(appSetGenerator, appSet)
return args.Get(0).([]map[string]any), args.Error(1)
}
func (g *generatorMock) GetRequeueAfter(appSetGenerator *v1alpha1.ApplicationSetGenerator) time.Duration {
args := g.Called(appSetGenerator)
return args.Get(0).(time.Duration)
}
func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
// Given a matrix generator over a list generator and a git files generator, the nested git files generator should
// be treated as a files generator, and it should produce parameters.
@@ -1072,11 +1050,11 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
// Now instead of checking for nil, we check whether the field is a non-empty slice. This test prevents a regression
// of that bug.
listGeneratorMock := &generatorMock{}
listGeneratorMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).Return([]map[string]any{
listGeneratorMock := &generatorsMock.Generator{}
listGeneratorMock.EXPECT().GenerateParams(mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).Return([]map[string]any{
{"some": "value"},
}, nil)
listGeneratorMock.On("GetTemplate", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator")).Return(&v1alpha1.ApplicationSetTemplate{})
listGeneratorMock.EXPECT().GetTemplate(mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator")).Return(&v1alpha1.ApplicationSetTemplate{})
gitGeneratorSpec := &v1alpha1.GitGenerator{
RepoURL: "https://git.example.com",
@@ -1085,10 +1063,10 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
},
}
repoServiceMock := &mocks.Repos{}
repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
repoServiceMock := &servicesMocks.Repos{}
repoServiceMock.EXPECT().GetFiles(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
"some/path.json": []byte("test: content"),
}, nil)
}, nil).Maybe()
gitGenerator := NewGitGenerator(repoServiceMock, "")
matrixGenerator := NewMatrixGenerator(map[string]Generator{

View File

@@ -1,7 +1,6 @@
package pull_request
import (
"context"
"errors"
"testing"
@@ -13,6 +12,7 @@ import (
"github.com/stretchr/testify/require"
azureMock "github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/azure_devops/git/mocks"
"github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/mocks"
)
func createBoolPtr(x bool) *bool {
@@ -35,29 +35,6 @@ func createUniqueNamePtr(x string) *string {
return &x
}
type AzureClientFactoryMock struct {
mock *mock.Mock
}
func (m *AzureClientFactoryMock) GetClient(ctx context.Context) (git.Client, error) {
args := m.mock.Called(ctx)
var client git.Client
c := args.Get(0)
if c != nil {
client = c.(git.Client)
}
var err error
if len(args) > 1 {
if e, ok := args.Get(1).(error); ok {
err = e
}
}
return client, err
}
func TestListPullRequest(t *testing.T) {
teamProject := "myorg_project"
repoName := "myorg_project_repo"
@@ -91,10 +68,10 @@ func TestListPullRequest(t *testing.T) {
SearchCriteria: &git.GitPullRequestSearchCriteria{},
}
gitClientMock := azureMock.Client{}
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, nil)
gitClientMock.On("GetPullRequestsByProject", ctx, args).Return(&pullRequestMock, nil)
gitClientMock := &azureMock.Client{}
clientFactoryMock := &mocks.AzureDevOpsClientFactory{}
clientFactoryMock.EXPECT().GetClient(mock.Anything).Return(gitClientMock, nil)
gitClientMock.EXPECT().GetPullRequestsByProject(mock.Anything, args).Return(&pullRequestMock, nil)
provider := AzureDevOpsService{
clientFactory: clientFactoryMock,
@@ -245,12 +222,12 @@ func TestAzureDevOpsListReturnsRepositoryNotFoundError(t *testing.T) {
pullRequestMock := []git.GitPullRequest{}
gitClientMock := azureMock.Client{}
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, nil)
gitClientMock := &azureMock.Client{}
clientFactoryMock := &mocks.AzureDevOpsClientFactory{}
clientFactoryMock.EXPECT().GetClient(mock.Anything).Return(gitClientMock, nil)
// Mock the GetPullRequestsByProject to return an error containing "404"
gitClientMock.On("GetPullRequestsByProject", t.Context(), args).Return(&pullRequestMock,
gitClientMock.EXPECT().GetPullRequestsByProject(mock.Anything, args).Return(&pullRequestMock,
errors.New("The following project does not exist:"))
provider := AzureDevOpsService{

View File

@@ -12,7 +12,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/aws_codecommit/mocks"
"github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/mocks"
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
)
@@ -177,9 +177,8 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
if repo.getRepositoryNilMetadata {
repoMetadata = nil
}
codeCommitClient.
On("GetRepositoryWithContext", ctx, &codecommit.GetRepositoryInput{RepositoryName: aws.String(repo.name)}).
Return(&codecommit.GetRepositoryOutput{RepositoryMetadata: repoMetadata}, repo.getRepositoryError)
codeCommitClient.EXPECT().GetRepositoryWithContext(mock.Anything, &codecommit.GetRepositoryInput{RepositoryName: aws.String(repo.name)}).
Return(&codecommit.GetRepositoryOutput{RepositoryMetadata: repoMetadata}, repo.getRepositoryError).Maybe()
codecommitRepoNameIdPairs = append(codecommitRepoNameIdPairs, &codecommit.RepositoryNameIdPair{
RepositoryId: aws.String(repo.id),
RepositoryName: aws.String(repo.name),
@@ -193,20 +192,18 @@ func TestAWSCodeCommitListRepos(t *testing.T) {
}
if testCase.expectListAtCodeCommit {
codeCommitClient.
On("ListRepositoriesWithContext", ctx, &codecommit.ListRepositoriesInput{}).
codeCommitClient.EXPECT().ListRepositoriesWithContext(mock.Anything, &codecommit.ListRepositoriesInput{}).
Return(&codecommit.ListRepositoriesOutput{
Repositories: codecommitRepoNameIdPairs,
}, testCase.listRepositoryError)
}, testCase.listRepositoryError).Maybe()
} else {
taggingClient.
On("GetResourcesWithContext", ctx, mock.MatchedBy(equalIgnoringTagFilterOrder(&resourcegroupstaggingapi.GetResourcesInput{
TagFilters: testCase.expectTagFilters,
ResourceTypeFilters: aws.StringSlice([]string{resourceTypeCodeCommitRepository}),
}))).
taggingClient.EXPECT().GetResourcesWithContext(mock.Anything, mock.MatchedBy(equalIgnoringTagFilterOrder(&resourcegroupstaggingapi.GetResourcesInput{
TagFilters: testCase.expectTagFilters,
ResourceTypeFilters: aws.StringSlice([]string{resourceTypeCodeCommitRepository}),
}))).
Return(&resourcegroupstaggingapi.GetResourcesOutput{
ResourceTagMappingList: resourceTaggings,
}, testCase.listRepositoryError)
}, testCase.listRepositoryError).Maybe()
}
provider := &AWSCodeCommitProvider{
@@ -350,13 +347,12 @@ func TestAWSCodeCommitRepoHasPath(t *testing.T) {
taggingClient := mocks.NewAWSTaggingClient(t)
ctx := t.Context()
if testCase.expectedGetFolderPath != "" {
codeCommitClient.
On("GetFolderWithContext", ctx, &codecommit.GetFolderInput{
CommitSpecifier: aws.String(branch),
FolderPath: aws.String(testCase.expectedGetFolderPath),
RepositoryName: aws.String(repoName),
}).
Return(testCase.getFolderOutput, testCase.getFolderError)
codeCommitClient.EXPECT().GetFolderWithContext(mock.Anything, &codecommit.GetFolderInput{
CommitSpecifier: aws.String(branch),
FolderPath: aws.String(testCase.expectedGetFolderPath),
RepositoryName: aws.String(repoName),
}).
Return(testCase.getFolderOutput, testCase.getFolderError).Maybe()
}
provider := &AWSCodeCommitProvider{
codeCommitClient: codeCommitClient,
@@ -423,18 +419,16 @@ func TestAWSCodeCommitGetBranches(t *testing.T) {
taggingClient := mocks.NewAWSTaggingClient(t)
ctx := t.Context()
if testCase.allBranches {
codeCommitClient.
On("ListBranchesWithContext", ctx, &codecommit.ListBranchesInput{
RepositoryName: aws.String(name),
}).
Return(&codecommit.ListBranchesOutput{Branches: aws.StringSlice(testCase.branches)}, testCase.apiError)
codeCommitClient.EXPECT().ListBranchesWithContext(mock.Anything, &codecommit.ListBranchesInput{
RepositoryName: aws.String(name),
}).
Return(&codecommit.ListBranchesOutput{Branches: aws.StringSlice(testCase.branches)}, testCase.apiError).Maybe()
} else {
codeCommitClient.
On("GetRepositoryWithContext", ctx, &codecommit.GetRepositoryInput{RepositoryName: aws.String(name)}).
codeCommitClient.EXPECT().GetRepositoryWithContext(mock.Anything, &codecommit.GetRepositoryInput{RepositoryName: aws.String(name)}).
Return(&codecommit.GetRepositoryOutput{RepositoryMetadata: &codecommit.RepositoryMetadata{
AccountId: aws.String(organization),
DefaultBranch: aws.String(defaultBranch),
}}, testCase.apiError)
}}, testCase.apiError).Maybe()
}
provider := &AWSCodeCommitProvider{
codeCommitClient: codeCommitClient,

View File

@@ -1,7 +1,6 @@
package scm_provider
import (
"context"
"errors"
"fmt"
"testing"
@@ -16,6 +15,7 @@ import (
azureGit "github.com/microsoft/azure-devops-go-api/azuredevops/v7/git"
azureMock "github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/azure_devops/git/mocks"
"github.com/argoproj/argo-cd/v3/applicationset/services/scm_provider/mocks"
)
func s(input string) *string {
@@ -78,13 +78,13 @@ func TestAzureDevopsRepoHasPath(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
gitClientMock := azureMock.Client{}
gitClientMock := &azureMock.Client{}
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, testCase.clientError)
clientFactoryMock := &mocks.AzureDevOpsClientFactory{}
clientFactoryMock.EXPECT().GetClient(mock.Anything).Return(gitClientMock, testCase.clientError)
repoId := &uuid
gitClientMock.On("GetItem", ctx, azureGit.GetItemArgs{Project: &teamProject, Path: &path, VersionDescriptor: &azureGit.GitVersionDescriptor{Version: &branchName}, RepositoryId: repoId}).Return(nil, testCase.azureDevopsError)
gitClientMock.EXPECT().GetItem(mock.Anything, azureGit.GetItemArgs{Project: &teamProject, Path: &path, VersionDescriptor: &azureGit.GitVersionDescriptor{Version: &branchName}, RepositoryId: repoId}).Return(nil, testCase.azureDevopsError)
provider := AzureDevOpsProvider{organization: organization, teamProject: teamProject, clientFactory: clientFactoryMock}
@@ -143,12 +143,12 @@ func TestGetDefaultBranchOnDisabledRepo(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) {
uuid := uuid.New().String()
gitClientMock := azureMock.Client{}
gitClientMock := azureMock.NewClient(t)
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, nil)
clientFactoryMock := &mocks.AzureDevOpsClientFactory{}
clientFactoryMock.EXPECT().GetClient(mock.Anything).Return(gitClientMock, nil)
gitClientMock.On("GetBranch", ctx, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &defaultBranch}).Return(nil, testCase.azureDevOpsError)
gitClientMock.EXPECT().GetBranch(mock.Anything, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &defaultBranch}).Return(nil, testCase.azureDevOpsError)
repo := &Repository{Organization: organization, Repository: repoName, RepositoryId: uuid, Branch: defaultBranch}
@@ -162,8 +162,6 @@ func TestGetDefaultBranchOnDisabledRepo(t *testing.T) {
}
assert.Empty(t, branches)
gitClientMock.AssertExpectations(t)
})
}
}
@@ -202,12 +200,12 @@ func TestGetAllBranchesOnDisabledRepo(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) {
uuid := uuid.New().String()
gitClientMock := azureMock.Client{}
gitClientMock := azureMock.NewClient(t)
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, nil)
clientFactoryMock := &mocks.AzureDevOpsClientFactory{}
clientFactoryMock.EXPECT().GetClient(mock.Anything).Return(gitClientMock, nil)
gitClientMock.On("GetBranches", ctx, azureGit.GetBranchesArgs{RepositoryId: &repoName, Project: &teamProject}).Return(nil, testCase.azureDevOpsError)
gitClientMock.EXPECT().GetBranches(mock.Anything, azureGit.GetBranchesArgs{RepositoryId: &repoName, Project: &teamProject}).Return(nil, testCase.azureDevOpsError)
repo := &Repository{Organization: organization, Repository: repoName, RepositoryId: uuid, Branch: defaultBranch}
@@ -221,8 +219,6 @@ func TestGetAllBranchesOnDisabledRepo(t *testing.T) {
}
assert.Empty(t, branches)
gitClientMock.AssertExpectations(t)
})
}
}
@@ -241,12 +237,12 @@ func TestAzureDevOpsGetDefaultBranchStripsRefsName(t *testing.T) {
branchReturn := &azureGit.GitBranchStats{Name: &strippedBranchName, Commit: &azureGit.GitCommitRef{CommitId: s("abc123233223")}}
repo := &Repository{Organization: organization, Repository: repoName, RepositoryId: uuid, Branch: defaultBranch}
gitClientMock := azureMock.Client{}
gitClientMock := &azureMock.Client{}
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, nil)
clientFactoryMock := &mocks.AzureDevOpsClientFactory{}
clientFactoryMock.EXPECT().GetClient(mock.Anything).Return(gitClientMock, nil)
gitClientMock.On("GetBranch", ctx, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &strippedBranchName}).Return(branchReturn, nil)
gitClientMock.EXPECT().GetBranch(mock.Anything, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &strippedBranchName}).Return(branchReturn, nil).Maybe()
provider := AzureDevOpsProvider{organization: organization, teamProject: teamProject, clientFactory: clientFactoryMock, allBranches: false}
branches, err := provider.GetBranches(ctx, repo)
@@ -295,12 +291,12 @@ func TestAzureDevOpsGetBranchesDefultBranchOnly(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
gitClientMock := azureMock.Client{}
gitClientMock := &azureMock.Client{}
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, testCase.clientError)
clientFactoryMock := &mocks.AzureDevOpsClientFactory{}
clientFactoryMock.EXPECT().GetClient(mock.Anything).Return(gitClientMock, testCase.clientError)
gitClientMock.On("GetBranch", ctx, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &defaultBranch}).Return(testCase.expectedBranch, testCase.getBranchesAPIError)
gitClientMock.EXPECT().GetBranch(mock.Anything, azureGit.GetBranchArgs{RepositoryId: &repoName, Project: &teamProject, Name: &defaultBranch}).Return(testCase.expectedBranch, testCase.getBranchesAPIError)
repo := &Repository{Organization: organization, Repository: repoName, RepositoryId: uuid, Branch: defaultBranch}
@@ -379,12 +375,12 @@ func TestAzureDevopsGetBranches(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
gitClientMock := azureMock.Client{}
gitClientMock := &azureMock.Client{}
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, testCase.clientError)
clientFactoryMock := &mocks.AzureDevOpsClientFactory{}
clientFactoryMock.EXPECT().GetClient(mock.Anything).Return(gitClientMock, testCase.clientError)
gitClientMock.On("GetBranches", ctx, azureGit.GetBranchesArgs{RepositoryId: &repoName, Project: &teamProject}).Return(testCase.expectedBranches, testCase.getBranchesAPIError)
gitClientMock.EXPECT().GetBranches(mock.Anything, azureGit.GetBranchesArgs{RepositoryId: &repoName, Project: &teamProject}).Return(testCase.expectedBranches, testCase.getBranchesAPIError)
repo := &Repository{Organization: organization, Repository: repoName, RepositoryId: uuid}
@@ -427,7 +423,6 @@ func TestGetAzureDevopsRepositories(t *testing.T) {
teamProject := "myorg_project"
uuid := uuid.New()
ctx := t.Context()
repoId := &uuid
@@ -477,15 +472,15 @@ func TestGetAzureDevopsRepositories(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
gitClientMock := azureMock.Client{}
gitClientMock.On("GetRepositories", ctx, azureGit.GetRepositoriesArgs{Project: s(teamProject)}).Return(&testCase.repositories, testCase.getRepositoriesError)
gitClientMock := azureMock.NewClient(t)
gitClientMock.EXPECT().GetRepositories(mock.Anything, azureGit.GetRepositoriesArgs{Project: s(teamProject)}).Return(&testCase.repositories, testCase.getRepositoriesError)
clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}}
clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock)
clientFactoryMock := &mocks.AzureDevOpsClientFactory{}
clientFactoryMock.EXPECT().GetClient(mock.Anything).Return(gitClientMock, nil)
provider := AzureDevOpsProvider{organization: organization, teamProject: teamProject, clientFactory: clientFactoryMock}
repositories, err := provider.ListRepos(ctx, "https")
repositories, err := provider.ListRepos(t.Context(), "https")
if testCase.getRepositoriesError != nil {
require.Error(t, err, "Expected an error from test case %v", testCase.name)
@@ -497,31 +492,6 @@ func TestGetAzureDevopsRepositories(t *testing.T) {
assert.NotEmpty(t, repositories)
assert.Len(t, repositories, testCase.expectedNumberOfRepos)
}
gitClientMock.AssertExpectations(t)
})
}
}
type AzureClientFactoryMock struct {
mock *mock.Mock
}
func (m *AzureClientFactoryMock) GetClient(ctx context.Context) (azureGit.Client, error) {
args := m.mock.Called(ctx)
var client azureGit.Client
c := args.Get(0)
if c != nil {
client = c.(azureGit.Client)
}
var err error
if len(args) > 1 {
if e, ok := args.Get(1).(error); ok {
err = e
}
}
return client, err
}

View File

@@ -0,0 +1,101 @@
// Code generated by mockery; DO NOT EDIT.
// github.com/vektra/mockery
// template: testify
package mocks
import (
"context"
"github.com/microsoft/azure-devops-go-api/azuredevops/v7/git"
mock "github.com/stretchr/testify/mock"
)
// NewAzureDevOpsClientFactory creates a new instance of AzureDevOpsClientFactory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewAzureDevOpsClientFactory(t interface {
mock.TestingT
Cleanup(func())
}) *AzureDevOpsClientFactory {
mock := &AzureDevOpsClientFactory{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
// AzureDevOpsClientFactory is an autogenerated mock type for the AzureDevOpsClientFactory type
type AzureDevOpsClientFactory struct {
mock.Mock
}
type AzureDevOpsClientFactory_Expecter struct {
mock *mock.Mock
}
func (_m *AzureDevOpsClientFactory) EXPECT() *AzureDevOpsClientFactory_Expecter {
return &AzureDevOpsClientFactory_Expecter{mock: &_m.Mock}
}
// GetClient provides a mock function for the type AzureDevOpsClientFactory
func (_mock *AzureDevOpsClientFactory) GetClient(ctx context.Context) (git.Client, error) {
ret := _mock.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for GetClient")
}
var r0 git.Client
var r1 error
if returnFunc, ok := ret.Get(0).(func(context.Context) (git.Client, error)); ok {
return returnFunc(ctx)
}
if returnFunc, ok := ret.Get(0).(func(context.Context) git.Client); ok {
r0 = returnFunc(ctx)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(git.Client)
}
}
if returnFunc, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = returnFunc(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// AzureDevOpsClientFactory_GetClient_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetClient'
type AzureDevOpsClientFactory_GetClient_Call struct {
*mock.Call
}
// GetClient is a helper method to define mock.On call
// - ctx context.Context
func (_e *AzureDevOpsClientFactory_Expecter) GetClient(ctx interface{}) *AzureDevOpsClientFactory_GetClient_Call {
return &AzureDevOpsClientFactory_GetClient_Call{Call: _e.mock.On("GetClient", ctx)}
}
func (_c *AzureDevOpsClientFactory_GetClient_Call) Run(run func(ctx context.Context)) *AzureDevOpsClientFactory_GetClient_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
arg0 = args[0].(context.Context)
}
run(
arg0,
)
})
return _c
}
func (_c *AzureDevOpsClientFactory_GetClient_Call) Return(client git.Client, err error) *AzureDevOpsClientFactory_GetClient_Call {
_c.Call.Return(client, err)
return _c
}
func (_c *AzureDevOpsClientFactory_GetClient_Call) RunAndReturn(run func(ctx context.Context) (git.Client, error)) *AzureDevOpsClientFactory_GetClient_Call {
_c.Call.Return(run)
return _c
}

View File

@@ -1,7 +1,6 @@
package services
import (
"context"
"crypto/tls"
"net/http"
"testing"
@@ -12,7 +11,7 @@ import (
)
func TestSetupBitbucketClient(t *testing.T) {
ctx := context.Background()
ctx := t.Context()
cfg := &bitbucketv1.Configuration{}
// Act

5
assets/swagger.json generated
View File

@@ -9480,6 +9480,11 @@
"connectionState": {
"$ref": "#/definitions/v1alpha1ConnectionState"
},
"depth": {
"description": "Depth specifies the depth for shallow clones. A value of 0 or omitting the field indicates a full clone.",
"type": "integer",
"format": "int64"
},
"enableLfs": {
"description": "EnableLFS specifies whether git-lfs support should be enabled for this repo. Only valid for Git repositories.",
"type": "boolean"

View File

@@ -105,26 +105,26 @@ func TestGetReconcileResults_Refresh(t *testing.T) {
appClientset := appfake.NewSimpleClientset(app, proj)
deployment := test.NewDeployment()
kubeClientset := kubefake.NewClientset(deployment, argoCM, argoCDSecret)
clusterCache := clustermocks.ClusterCache{}
clusterCache.On("IsNamespaced", mock.Anything).Return(true, nil)
clusterCache.On("GetGVKParser", mock.Anything).Return(nil)
repoServerClient := mocks.RepoServerServiceClient{}
repoServerClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(&argocdclient.ManifestResponse{
clusterCache := &clustermocks.ClusterCache{}
clusterCache.EXPECT().IsNamespaced(mock.Anything).Return(true, nil)
clusterCache.EXPECT().GetGVKParser().Return(nil)
repoServerClient := &mocks.RepoServerServiceClient{}
repoServerClient.EXPECT().GenerateManifest(mock.Anything, mock.Anything).Return(&argocdclient.ManifestResponse{
Manifests: []string{test.DeploymentManifest},
}, nil)
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
liveStateCache := cachemocks.LiveStateCache{}
liveStateCache.On("GetManagedLiveObjs", mock.Anything, mock.Anything, mock.Anything).Return(map[kube.ResourceKey]*unstructured.Unstructured{
repoServerClientset := &mocks.Clientset{RepoServerServiceClient: repoServerClient}
liveStateCache := &cachemocks.LiveStateCache{}
liveStateCache.EXPECT().GetManagedLiveObjs(mock.Anything, mock.Anything, mock.Anything).Return(map[kube.ResourceKey]*unstructured.Unstructured{
kube.GetResourceKey(deployment): deployment,
}, nil)
liveStateCache.On("GetVersionsInfo", mock.Anything).Return("v1.2.3", nil, nil)
liveStateCache.On("Init").Return(nil, nil)
liveStateCache.On("GetClusterCache", mock.Anything).Return(&clusterCache, nil)
liveStateCache.On("IsNamespaced", mock.Anything, mock.Anything).Return(true, nil)
liveStateCache.EXPECT().GetVersionsInfo(mock.Anything).Return("v1.2.3", nil, nil)
liveStateCache.EXPECT().Init().Return(nil)
liveStateCache.EXPECT().GetClusterCache(mock.Anything).Return(clusterCache, nil)
liveStateCache.EXPECT().IsNamespaced(mock.Anything, mock.Anything).Return(true, nil)
result, err := reconcileApplications(ctx, kubeClientset, appClientset, "default", &repoServerClientset, "",
result, err := reconcileApplications(ctx, kubeClientset, appClientset, "default", repoServerClientset, "",
func(_ db.ArgoDB, _ cache.SharedIndexInformer, _ *settings.SettingsManager, _ *metrics.MetricsServer) statecache.LiveStateCache {
return &liveStateCache
return liveStateCache
},
false,
normalizers.IgnoreNormalizerOpts{},

View File

@@ -40,9 +40,7 @@ func captureStdout(callback func()) (string, error) {
return string(data), err
}
func newSettingsManager(data map[string]string) *settings.SettingsManager {
ctx := context.Background()
func newSettingsManager(ctx context.Context, data map[string]string) *settings.SettingsManager {
clientset := fake.NewClientset(&corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: "default",
@@ -69,8 +67,8 @@ type fakeCmdContext struct {
mgr *settings.SettingsManager
}
func newCmdContext(data map[string]string) *fakeCmdContext {
return &fakeCmdContext{mgr: newSettingsManager(data)}
func newCmdContext(ctx context.Context, data map[string]string) *fakeCmdContext {
return &fakeCmdContext{mgr: newSettingsManager(ctx, data)}
}
func (ctx *fakeCmdContext) createSettingsManager(context.Context) (*settings.SettingsManager, error) {
@@ -182,7 +180,7 @@ admissionregistration.k8s.io/MutatingWebhookConfiguration:
if !assert.True(t, ok) {
return
}
summary, err := validator(newSettingsManager(tc.data))
summary, err := validator(newSettingsManager(t.Context(), tc.data))
if tc.containsSummary != "" {
require.NoError(t, err)
assert.Contains(t, summary, tc.containsSummary)
@@ -249,7 +247,7 @@ func tempFile(content string) (string, io.Closer, error) {
}
func TestValidateSettingsCommand_NoErrors(t *testing.T) {
cmd := NewValidateSettingsCommand(newCmdContext(map[string]string{}))
cmd := NewValidateSettingsCommand(newCmdContext(t.Context(), map[string]string{}))
out, err := captureStdout(func() {
err := cmd.Execute()
require.NoError(t, err)
@@ -267,7 +265,7 @@ func TestResourceOverrideIgnoreDifferences(t *testing.T) {
defer utilio.Close(closer)
t.Run("NoOverridesConfigured", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{}))
cmd := NewResourceOverridesCommand(newCmdContext(t.Context(), map[string]string{}))
out, err := captureStdout(func() {
cmd.SetArgs([]string{"ignore-differences", f})
err := cmd.Execute()
@@ -278,7 +276,7 @@ func TestResourceOverrideIgnoreDifferences(t *testing.T) {
})
t.Run("DataIgnored", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
cmd := NewResourceOverridesCommand(newCmdContext(t.Context(), map[string]string{
"resource.customizations": `apps/Deployment:
ignoreDifferences: |
jsonPointers:
@@ -300,7 +298,7 @@ func TestResourceOverrideHealth(t *testing.T) {
defer utilio.Close(closer)
t.Run("NoHealthAssessment", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
cmd := NewResourceOverridesCommand(newCmdContext(t.Context(), map[string]string{
"resource.customizations": `example.com/ExampleResource: {}`,
}))
out, err := captureStdout(func() {
@@ -313,7 +311,7 @@ func TestResourceOverrideHealth(t *testing.T) {
})
t.Run("HealthAssessmentConfigured", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
cmd := NewResourceOverridesCommand(newCmdContext(t.Context(), map[string]string{
"resource.customizations": `example.com/ExampleResource:
health.lua: |
return { status = "Progressing" }
@@ -329,7 +327,7 @@ func TestResourceOverrideHealth(t *testing.T) {
})
t.Run("HealthAssessmentConfiguredWildcard", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
cmd := NewResourceOverridesCommand(newCmdContext(t.Context(), map[string]string{
"resource.customizations": `example.com/*:
health.lua: |
return { status = "Progressing" }
@@ -355,7 +353,7 @@ func TestResourceOverrideAction(t *testing.T) {
defer utilio.Close(closer)
t.Run("NoActions", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
cmd := NewResourceOverridesCommand(newCmdContext(t.Context(), map[string]string{
"resource.customizations": `apps/Deployment: {}`,
}))
out, err := captureStdout(func() {
@@ -368,7 +366,7 @@ func TestResourceOverrideAction(t *testing.T) {
})
t.Run("OldStyleActionConfigured", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
cmd := NewResourceOverridesCommand(newCmdContext(t.Context(), map[string]string{
"resource.customizations": `apps/Deployment:
actions: |
discovery.lua: |
@@ -404,7 +402,7 @@ resume false
})
t.Run("NewStyleActionConfigured", func(t *testing.T) {
cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{
cmd := NewResourceOverridesCommand(newCmdContext(t.Context(), map[string]string{
"resource.customizations": `batch/CronJob:
actions: |
discovery.lua: |

View File

@@ -191,6 +191,7 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
repoOpts.Repo.NoProxy = repoOpts.NoProxy
repoOpts.Repo.ForceHttpBasicAuth = repoOpts.ForceHttpBasicAuth
repoOpts.Repo.UseAzureWorkloadIdentity = repoOpts.UseAzureWorkloadIdentity
repoOpts.Repo.Depth = repoOpts.Depth
if repoOpts.Repo.Type == "helm" && repoOpts.Repo.Name == "" {
errors.Fatal(errors.ErrorGeneric, "Must specify --name for repos of type 'helm'")

View File

@@ -27,6 +27,7 @@ type RepoOptions struct {
GCPServiceAccountKeyPath string
ForceHttpBasicAuth bool //nolint:revive //FIXME(var-naming)
UseAzureWorkloadIdentity bool
Depth int64
}
func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
@@ -53,4 +54,5 @@ func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
command.Flags().BoolVar(&opts.ForceHttpBasicAuth, "force-http-basic-auth", false, "whether to force use of basic auth when connecting repository via HTTP")
command.Flags().BoolVar(&opts.UseAzureWorkloadIdentity, "use-azure-workload-identity", false, "whether to use azure workload identity for authentication")
command.Flags().BoolVar(&opts.InsecureOCIForceHTTP, "insecure-oci-force-http", false, "Use http when accessing an OCI repository")
command.Flags().Int64Var(&opts.Depth, "depth", 0, "Specify a custom depth for git clone operations. Unless specified, a full clone is performed using the depth of 0")
}

View File

@@ -229,7 +229,7 @@ func (s *Service) initGitClient(logCtx *log.Entry, r *apiclient.CommitHydratedMa
}
logCtx.Debugf("Fetching repo %s", r.Repo.Repo)
err = gitClient.Fetch("")
err = gitClient.Fetch("", 0)
if err != nil {
cleanupOrLog()
return nil, "", nil, fmt.Errorf("failed to clone repo: %w", err)

View File

@@ -82,7 +82,7 @@ func Test_CommitHydratedManifests(t *testing.T) {
t.Parallel()
service, mockRepoClientFactory := newServiceWithMocks(t)
mockRepoClientFactory.On("NewClient", mock.Anything, mock.Anything).Return(nil, assert.AnError).Once()
mockRepoClientFactory.EXPECT().NewClient(mock.Anything, mock.Anything).Return(nil, assert.AnError).Once()
_, err := service.CommitHydratedManifests(t.Context(), validRequest)
require.Error(t, err)
@@ -94,14 +94,14 @@ func Test_CommitHydratedManifests(t *testing.T) {
service, mockRepoClientFactory := newServiceWithMocks(t)
mockGitClient := gitmocks.NewClient(t)
mockGitClient.On("Init").Return(nil).Once()
mockGitClient.On("Fetch", mock.Anything).Return(nil).Once()
mockGitClient.On("SetAuthor", "Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.On("CheckoutOrOrphan", "env/test", false).Return("", nil).Once()
mockGitClient.On("CheckoutOrNew", "main", "env/test", false).Return("", nil).Once()
mockGitClient.On("CommitAndPush", "main", "test commit message").Return("", nil).Once()
mockGitClient.On("CommitSHA").Return("it-worked!", nil).Once()
mockRepoClientFactory.On("NewClient", mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
mockGitClient.EXPECT().Init().Return(nil).Once()
mockGitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil).Once()
mockGitClient.EXPECT().SetAuthor("Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrOrphan("env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrNew("main", "env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().CommitAndPush("main", "test commit message").Return("", nil).Once()
mockGitClient.EXPECT().CommitSHA().Return("it-worked!", nil).Once()
mockRepoClientFactory.EXPECT().NewClient(mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
resp, err := service.CommitHydratedManifests(t.Context(), validRequest)
require.NoError(t, err)
@@ -114,14 +114,14 @@ func Test_CommitHydratedManifests(t *testing.T) {
service, mockRepoClientFactory := newServiceWithMocks(t)
mockGitClient := gitmocks.NewClient(t)
mockGitClient.On("Init").Return(nil).Once()
mockGitClient.On("Fetch", mock.Anything).Return(nil).Once()
mockGitClient.On("SetAuthor", "Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.On("CheckoutOrOrphan", "env/test", false).Return("", nil).Once()
mockGitClient.On("CheckoutOrNew", "main", "env/test", false).Return("", nil).Once()
mockGitClient.On("CommitAndPush", "main", "test commit message").Return("", nil).Once()
mockGitClient.On("CommitSHA").Return("root-and-blank-sha", nil).Once()
mockRepoClientFactory.On("NewClient", mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
mockGitClient.EXPECT().Init().Return(nil).Once()
mockGitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil).Once()
mockGitClient.EXPECT().SetAuthor("Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrOrphan("env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrNew("main", "env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().CommitAndPush("main", "test commit message").Return("", nil).Once()
mockGitClient.EXPECT().CommitSHA().Return("root-and-blank-sha", nil).Once()
mockRepoClientFactory.EXPECT().NewClient(mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
requestWithRootAndBlank := &apiclient.CommitHydratedManifestsRequest{
Repo: &v1alpha1.Repository{
@@ -161,15 +161,15 @@ func Test_CommitHydratedManifests(t *testing.T) {
service, mockRepoClientFactory := newServiceWithMocks(t)
mockGitClient := gitmocks.NewClient(t)
mockGitClient.On("Init").Return(nil).Once()
mockGitClient.On("Fetch", mock.Anything).Return(nil).Once()
mockGitClient.On("SetAuthor", "Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.On("CheckoutOrOrphan", "env/test", false).Return("", nil).Once()
mockGitClient.On("CheckoutOrNew", "main", "env/test", false).Return("", nil).Once()
mockGitClient.On("RemoveContents", []string{"apps/staging"}).Return("", nil).Once()
mockGitClient.On("CommitAndPush", "main", "test commit message").Return("", nil).Once()
mockGitClient.On("CommitSHA").Return("subdir-path-sha", nil).Once()
mockRepoClientFactory.On("NewClient", mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
mockGitClient.EXPECT().Init().Return(nil).Once()
mockGitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil).Once()
mockGitClient.EXPECT().SetAuthor("Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrOrphan("env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrNew("main", "env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().RemoveContents([]string{"apps/staging"}).Return("", nil).Once()
mockGitClient.EXPECT().CommitAndPush("main", "test commit message").Return("", nil).Once()
mockGitClient.EXPECT().CommitSHA().Return("subdir-path-sha", nil).Once()
mockRepoClientFactory.EXPECT().NewClient(mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
requestWithSubdirPath := &apiclient.CommitHydratedManifestsRequest{
Repo: &v1alpha1.Repository{
@@ -201,15 +201,15 @@ func Test_CommitHydratedManifests(t *testing.T) {
service, mockRepoClientFactory := newServiceWithMocks(t)
mockGitClient := gitmocks.NewClient(t)
mockGitClient.On("Init").Return(nil).Once()
mockGitClient.On("Fetch", mock.Anything).Return(nil).Once()
mockGitClient.On("SetAuthor", "Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.On("CheckoutOrOrphan", "env/test", false).Return("", nil).Once()
mockGitClient.On("CheckoutOrNew", "main", "env/test", false).Return("", nil).Once()
mockGitClient.On("RemoveContents", []string{"apps/production", "apps/staging"}).Return("", nil).Once()
mockGitClient.On("CommitAndPush", "main", "test commit message").Return("", nil).Once()
mockGitClient.On("CommitSHA").Return("mixed-paths-sha", nil).Once()
mockRepoClientFactory.On("NewClient", mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
mockGitClient.EXPECT().Init().Return(nil).Once()
mockGitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil).Once()
mockGitClient.EXPECT().SetAuthor("Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrOrphan("env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrNew("main", "env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().RemoveContents([]string{"apps/production", "apps/staging"}).Return("", nil).Once()
mockGitClient.EXPECT().CommitAndPush("main", "test commit message").Return("", nil).Once()
mockGitClient.EXPECT().CommitSHA().Return("mixed-paths-sha", nil).Once()
mockRepoClientFactory.EXPECT().NewClient(mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
requestWithMixedPaths := &apiclient.CommitHydratedManifestsRequest{
Repo: &v1alpha1.Repository{
@@ -257,14 +257,14 @@ func Test_CommitHydratedManifests(t *testing.T) {
service, mockRepoClientFactory := newServiceWithMocks(t)
mockGitClient := gitmocks.NewClient(t)
mockGitClient.On("Init").Return(nil).Once()
mockGitClient.On("Fetch", mock.Anything).Return(nil).Once()
mockGitClient.On("SetAuthor", "Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.On("CheckoutOrOrphan", "env/test", false).Return("", nil).Once()
mockGitClient.On("CheckoutOrNew", "main", "env/test", false).Return("", nil).Once()
mockGitClient.On("CommitAndPush", "main", "test commit message").Return("", nil).Once()
mockGitClient.On("CommitSHA").Return("it-worked!", nil).Once()
mockRepoClientFactory.On("NewClient", mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
mockGitClient.EXPECT().Init().Return(nil).Once()
mockGitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil).Once()
mockGitClient.EXPECT().SetAuthor("Argo CD", "argo-cd@example.com").Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrOrphan("env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().CheckoutOrNew("main", "env/test", false).Return("", nil).Once()
mockGitClient.EXPECT().CommitAndPush("main", "test commit message").Return("", nil).Once()
mockGitClient.EXPECT().CommitSHA().Return("it-worked!", nil).Once()
mockRepoClientFactory.EXPECT().NewClient(mock.Anything, mock.Anything).Return(mockGitClient, nil).Once()
requestWithEmptyPaths := &apiclient.CommitHydratedManifestsRequest{
Repo: &v1alpha1.Repository{

View File

@@ -95,11 +95,11 @@ func (m *MockKubectl) DeleteResource(ctx context.Context, config *rest.Config, g
return m.Kubectl.DeleteResource(ctx, config, gvk, name, namespace, deleteOptions)
}
func newFakeController(data *fakeData, repoErr error) *ApplicationController {
return newFakeControllerWithResync(data, time.Minute, repoErr, nil)
func newFakeController(ctx context.Context, data *fakeData, repoErr error) *ApplicationController {
return newFakeControllerWithResync(ctx, data, time.Minute, repoErr, nil)
}
func newFakeControllerWithResync(data *fakeData, appResyncPeriod time.Duration, repoErr, revisionPathsErr error) *ApplicationController {
func newFakeControllerWithResync(ctx context.Context, data *fakeData, appResyncPeriod time.Duration, repoErr, revisionPathsErr error) *ApplicationController {
var clust corev1.Secret
err := yaml.Unmarshal([]byte(fakeCluster), &clust)
if err != nil {
@@ -107,33 +107,33 @@ func newFakeControllerWithResync(data *fakeData, appResyncPeriod time.Duration,
}
// Mock out call to GenerateManifest
mockRepoClient := mockrepoclient.RepoServerServiceClient{}
mockRepoClient := &mockrepoclient.RepoServerServiceClient{}
if len(data.manifestResponses) > 0 {
for _, response := range data.manifestResponses {
if repoErr != nil {
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(response, repoErr).Once()
mockRepoClient.EXPECT().GenerateManifest(mock.Anything, mock.Anything).Return(response, repoErr).Once()
} else {
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(response, nil).Once()
mockRepoClient.EXPECT().GenerateManifest(mock.Anything, mock.Anything).Return(response, nil).Once()
}
}
} else {
if repoErr != nil {
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, repoErr).Once()
mockRepoClient.EXPECT().GenerateManifest(mock.Anything, mock.Anything).Return(data.manifestResponse, repoErr).Once()
} else {
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, nil).Once()
mockRepoClient.EXPECT().GenerateManifest(mock.Anything, mock.Anything).Return(data.manifestResponse, nil).Once()
}
}
if revisionPathsErr != nil {
mockRepoClient.On("UpdateRevisionForPaths", mock.Anything, mock.Anything).Return(nil, revisionPathsErr)
mockRepoClient.EXPECT().UpdateRevisionForPaths(mock.Anything, mock.Anything).Return(nil, revisionPathsErr)
} else {
mockRepoClient.On("UpdateRevisionForPaths", mock.Anything, mock.Anything).Return(data.updateRevisionForPathsResponse, nil)
mockRepoClient.EXPECT().UpdateRevisionForPaths(mock.Anything, mock.Anything).Return(data.updateRevisionForPathsResponse, nil)
}
mockRepoClientset := mockrepoclient.Clientset{RepoServerServiceClient: &mockRepoClient}
mockRepoClientset := &mockrepoclient.Clientset{RepoServerServiceClient: mockRepoClient}
mockCommitClientset := mockcommitclient.Clientset{}
mockCommitClientset := &mockcommitclient.Clientset{}
secret := corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
@@ -158,15 +158,15 @@ func newFakeControllerWithResync(data *fakeData, appResyncPeriod time.Duration,
runtimeObjs := []runtime.Object{&clust, &secret, &cm}
runtimeObjs = append(runtimeObjs, data.additionalObjs...)
kubeClient := fake.NewClientset(runtimeObjs...)
settingsMgr := settings.NewSettingsManager(context.Background(), kubeClient, test.FakeArgoCDNamespace)
settingsMgr := settings.NewSettingsManager(ctx, kubeClient, test.FakeArgoCDNamespace)
kubectl := &MockKubectl{Kubectl: &kubetest.MockKubectlCmd{}}
ctrl, err := NewApplicationController(
test.FakeArgoCDNamespace,
settingsMgr,
kubeClient,
appclientset.NewSimpleClientset(data.apps...),
&mockRepoClientset,
&mockCommitClientset,
mockRepoClientset,
mockCommitClientset,
appstatecache.NewCache(
cacheutil.NewCache(cacheutil.NewInMemoryCache(1*time.Minute)),
1*time.Minute,
@@ -197,7 +197,7 @@ func newFakeControllerWithResync(data *fakeData, appResyncPeriod time.Duration,
false,
)
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
db.EXPECT().GetApplicationControllerReplicas().Return(1).Maybe()
// Setting a default sharding algorithm for the tests where we cannot set it.
ctrl.clusterSharding = sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm)
if err != nil {
@@ -207,27 +207,25 @@ func newFakeControllerWithResync(data *fakeData, appResyncPeriod time.Duration,
defer cancelProj()
cancelApp := test.StartInformer(ctrl.appInformer)
defer cancelApp()
clusterCacheMock := mocks.ClusterCache{}
clusterCacheMock.On("IsNamespaced", mock.Anything).Return(true, nil)
clusterCacheMock.On("GetOpenAPISchema").Return(nil, nil)
clusterCacheMock.On("GetGVKParser").Return(nil)
clusterCacheMock := &mocks.ClusterCache{}
clusterCacheMock.EXPECT().IsNamespaced(mock.Anything).Return(true, nil)
clusterCacheMock.EXPECT().GetOpenAPISchema().Return(nil)
clusterCacheMock.EXPECT().GetGVKParser().Return(nil)
mockStateCache := mockstatecache.LiveStateCache{}
ctrl.appStateManager.(*appStateManager).liveStateCache = &mockStateCache
ctrl.stateCache = &mockStateCache
mockStateCache.On("IsNamespaced", mock.Anything, mock.Anything).Return(true, nil)
mockStateCache.On("GetManagedLiveObjs", mock.Anything, mock.Anything, mock.Anything).Return(data.managedLiveObjs, nil)
mockStateCache.On("GetVersionsInfo", mock.Anything).Return("v1.2.3", nil, nil)
mockStateCache := &mockstatecache.LiveStateCache{}
ctrl.appStateManager.(*appStateManager).liveStateCache = mockStateCache
ctrl.stateCache = mockStateCache
mockStateCache.EXPECT().IsNamespaced(mock.Anything, mock.Anything).Return(true, nil)
mockStateCache.EXPECT().GetManagedLiveObjs(mock.Anything, mock.Anything, mock.Anything).Return(data.managedLiveObjs, nil)
mockStateCache.EXPECT().GetVersionsInfo(mock.Anything).Return("v1.2.3", nil, nil)
response := make(map[kube.ResourceKey]v1alpha1.ResourceNode)
for k, v := range data.namespacedResources {
response[k] = v.ResourceNode
}
mockStateCache.On("GetNamespaceTopLevelResources", mock.Anything, mock.Anything).Return(response, nil)
mockStateCache.On("IterateResources", mock.Anything, mock.Anything).Return(nil)
mockStateCache.On("GetClusterCache", mock.Anything).Return(&clusterCacheMock, nil)
mockStateCache.On("IterateHierarchyV2", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
keys := args[1].([]kube.ResourceKey)
action := args[2].(func(child v1alpha1.ResourceNode, appName string) bool)
mockStateCache.EXPECT().GetNamespaceTopLevelResources(mock.Anything, mock.Anything).Return(response, nil)
mockStateCache.EXPECT().IterateResources(mock.Anything, mock.Anything).Return(nil)
mockStateCache.EXPECT().GetClusterCache(mock.Anything).Return(clusterCacheMock, nil)
mockStateCache.EXPECT().IterateHierarchyV2(mock.Anything, mock.Anything, mock.Anything).Run(func(_ *v1alpha1.Cluster, keys []kube.ResourceKey, action func(_ v1alpha1.ResourceNode, _ string) bool) {
for _, key := range keys {
appName := ""
if res, ok := data.namespacedResources[key]; ok {
@@ -597,7 +595,7 @@ func newFakeServiceAccount() map[string]any {
func TestAutoSync(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -615,7 +613,7 @@ func TestAutoSyncEnabledSetToTrue(t *testing.T) {
app := newFakeApp()
enable := true
app.Spec.SyncPolicy.Automated = &v1alpha1.SyncPolicyAutomated{Enabled: &enable}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -636,7 +634,7 @@ func TestAutoSyncMultiSourceWithoutSelfHeal(t *testing.T) {
app := newFakeMultiSourceApp()
app.Spec.SyncPolicy.Automated.SelfHeal = false
app.Status.OperationState.SyncResult.Revisions = []string{"z", "x", "v"}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revisions: []string{"z", "x", "v"},
@@ -651,7 +649,7 @@ func TestAutoSyncMultiSourceWithoutSelfHeal(t *testing.T) {
app := newFakeMultiSourceApp()
app.Spec.SyncPolicy.Automated.SelfHeal = false
app.Status.OperationState.SyncResult.Revisions = []string{"z", "x", "v"}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revisions: []string{"a", "b", "c"},
@@ -667,7 +665,7 @@ func TestAutoSyncMultiSourceWithoutSelfHeal(t *testing.T) {
func TestAutoSyncNotAllowEmpty(t *testing.T) {
app := newFakeApp()
app.Spec.SyncPolicy.Automated.Prune = true
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -680,7 +678,7 @@ func TestAutoSyncAllowEmpty(t *testing.T) {
app := newFakeApp()
app.Spec.SyncPolicy.Automated.Prune = true
app.Spec.SyncPolicy.Automated.AllowEmpty = true
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -694,7 +692,7 @@ func TestSkipAutoSync(t *testing.T) {
// Set current to 'aaaaa', desired to 'aaaa' and mark system OutOfSync
t.Run("PreviouslySyncedToRevision", func(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@@ -709,7 +707,7 @@ func TestSkipAutoSync(t *testing.T) {
// Verify we skip when we are already Synced (even if revision is different)
t.Run("AlreadyInSyncedState", func(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeSynced,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -725,7 +723,7 @@ func TestSkipAutoSync(t *testing.T) {
t.Run("AutoSyncIsDisabled", func(t *testing.T) {
app := newFakeApp()
app.Spec.SyncPolicy = nil
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -742,7 +740,7 @@ func TestSkipAutoSync(t *testing.T) {
app := newFakeApp()
enable := false
app.Spec.SyncPolicy.Automated = &v1alpha1.SyncPolicyAutomated{Enabled: &enable}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -759,7 +757,7 @@ func TestSkipAutoSync(t *testing.T) {
app := newFakeApp()
now := metav1.Now()
app.DeletionTimestamp = &now
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -785,7 +783,7 @@ func TestSkipAutoSync(t *testing.T) {
Source: *app.Spec.Source.DeepCopy(),
},
}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -809,7 +807,7 @@ func TestSkipAutoSync(t *testing.T) {
Source: *app.Spec.Source.DeepCopy(),
},
}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -823,7 +821,7 @@ func TestSkipAutoSync(t *testing.T) {
t.Run("NeedsToPruneResourcesOnlyButAutomatedPruneDisabled", func(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
@@ -849,7 +847,7 @@ func TestAutoSyncIndicateError(t *testing.T) {
},
},
}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
syncStatus := v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@@ -909,7 +907,7 @@ func TestAutoSyncParameterOverrides(t *testing.T) {
Status: v1alpha1.SyncStatusCodeOutOfSync,
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}, true)
assert.Nil(t, cond)
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(t.Context(), "my-app", metav1.GetOptions{})
@@ -927,7 +925,7 @@ func TestAutoSyncParameterOverrides(t *testing.T) {
},
},
}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
app.Status.OperationState.SyncResult.Revisions = []string{"z", "x", "v"}
app.Status.OperationState.SyncResult.Sources[0].Helm = &v1alpha1.ApplicationSourceHelm{
Parameters: []v1alpha1.HelmParameter{
@@ -974,7 +972,7 @@ func TestFinalizeAppDeletion(t *testing.T) {
app.SetCascadedDeletion(v1alpha1.ResourcesFinalizerName)
app.DeletionTimestamp = &now
app.Spec.Destination.Namespace = test.FakeArgoCDNamespace
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{}}, nil)
patched := false
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
defaultReactor := fakeAppCs.ReactionChain[0]
@@ -1019,7 +1017,7 @@ func TestFinalizeAppDeletion(t *testing.T) {
appObj := kube.MustToUnstructured(&app)
cm := newFakeCM()
strayObj := kube.MustToUnstructured(&cm)
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj, &restrictedProj},
managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{
kube.GetResourceKey(appObj): appObj,
@@ -1060,7 +1058,7 @@ func TestFinalizeAppDeletion(t *testing.T) {
app := newFakeAppWithDestName()
app.SetCascadedDeletion(v1alpha1.ResourcesFinalizerName)
app.DeletionTimestamp = &now
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{}}, nil)
patched := false
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
defaultReactor := fakeAppCs.ReactionChain[0]
@@ -1086,7 +1084,7 @@ func TestFinalizeAppDeletion(t *testing.T) {
testShouldDelete := func(app *v1alpha1.Application) {
appObj := kube.MustToUnstructured(&app)
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{
kube.GetResourceKey(appObj): appObj,
}}, nil)
@@ -1120,7 +1118,7 @@ func TestFinalizeAppDeletion(t *testing.T) {
app := newFakeApp()
app.SetPostDeleteFinalizer()
app.Spec.Destination.Namespace = test.FakeArgoCDNamespace
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
manifestResponses: []*apiclient.ManifestResponse{{
Manifests: []string{fakePostDeleteHook},
}},
@@ -1162,7 +1160,7 @@ func TestFinalizeAppDeletion(t *testing.T) {
},
}
require.NoError(t, unstructured.SetNestedField(liveHook.Object, conditions, "status", "conditions"))
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
manifestResponses: []*apiclient.ManifestResponse{{
Manifests: []string{fakePostDeleteHook},
}},
@@ -1206,7 +1204,7 @@ func TestFinalizeAppDeletion(t *testing.T) {
},
}
require.NoError(t, unstructured.SetNestedField(liveHook.Object, conditions, "status", "conditions"))
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
manifestResponses: []*apiclient.ManifestResponse{{
Manifests: []string{fakeRoleBinding, fakeRole, fakeServiceAccount, fakePostDeleteHook},
}},
@@ -1308,7 +1306,7 @@ func TestFinalizeAppDeletionWithImpersonation(t *testing.T) {
},
additionalObjs: additionalObjs,
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
return &fixture{
application: app,
controller: ctrl,
@@ -1391,7 +1389,7 @@ func TestNormalizeApplication(t *testing.T) {
{
// Verify we normalize the app because project is missing
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
key, _ := cache.MetaNamespaceKeyFunc(app)
ctrl.appRefreshQueue.AddRateLimited(key)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
@@ -1413,7 +1411,7 @@ func TestNormalizeApplication(t *testing.T) {
// Verify we don't unnecessarily normalize app when project is set
app.Spec.Project = "default"
data.apps[0] = app
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
key, _ := cache.MetaNamespaceKeyFunc(app)
ctrl.appRefreshQueue.AddRateLimited(key)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
@@ -1438,7 +1436,7 @@ func TestHandleAppUpdated(t *testing.T) {
app.Spec.Destination.Server = v1alpha1.KubernetesInternalAPIServerAddr
proj := defaultProj.DeepCopy()
proj.Spec.SourceNamespaces = []string{test.FakeArgoCDNamespace}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, proj}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app, proj}}, nil)
ctrl.handleObjectUpdated(map[string]bool{app.InstanceName(ctrl.namespace): true}, kube.GetObjectRef(kube.MustToUnstructured(app)))
isRequested, level := ctrl.isRefreshRequested(app.QualifiedName())
@@ -1465,7 +1463,7 @@ func TestHandleOrphanedResourceUpdated(t *testing.T) {
proj := defaultProj.DeepCopy()
proj.Spec.OrphanedResources = &v1alpha1.OrphanedResourcesMonitorSettings{}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app1, app2, proj}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app1, app2, proj}}, nil)
ctrl.handleObjectUpdated(map[string]bool{}, corev1.ObjectReference{UID: "test", Kind: kube.DeploymentKind, Name: "test", Namespace: test.FakeArgoCDNamespace})
@@ -1496,7 +1494,7 @@ func TestGetResourceTree_HasOrphanedResources(t *testing.T) {
ResourceRef: v1alpha1.ResourceRef{Group: "apps", Kind: "Deployment", Namespace: "default", Name: "deploy2"},
}
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, proj},
namespacedResources: map[kube.ResourceKey]namespacedResource{
kube.NewResourceKey("apps", "Deployment", "default", "nginx-deployment"): {ResourceNode: managedDeploy},
@@ -1519,7 +1517,7 @@ func TestGetResourceTree_HasOrphanedResources(t *testing.T) {
}
func TestSetOperationStateOnDeletedApp(t *testing.T) {
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{}}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
fakeAppCs.ReactionChain = nil
patched := false
@@ -1537,7 +1535,7 @@ func TestSetOperationStateLogRetries(t *testing.T) {
t.Cleanup(func() {
logrus.StandardLogger().ReplaceHooks(logrus.LevelHooks{})
})
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{}}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
fakeAppCs.ReactionChain = nil
patched := false
@@ -1593,7 +1591,7 @@ func TestNeedRefreshAppStatus(t *testing.T) {
app.Status.Sync.ComparedTo.Source = app.Spec.GetSource()
}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{}}, nil)
t.Run("no need to refresh just reconciled application", func(t *testing.T) {
needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
@@ -1605,7 +1603,7 @@ func TestNeedRefreshAppStatus(t *testing.T) {
assert.False(t, needRefresh)
// use a one-off controller so other tests don't have a manual refresh request
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{}}, nil)
// refresh app using the 'deepest' requested comparison level
ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil)
@@ -1622,7 +1620,7 @@ func TestNeedRefreshAppStatus(t *testing.T) {
assert.False(t, needRefresh)
// use a one-off controller so other tests don't have a manual refresh request
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{}}, nil)
// refresh app with a non-nil delay
// use zero-second delay to test the add later logic without waiting in the test
@@ -1652,7 +1650,7 @@ func TestNeedRefreshAppStatus(t *testing.T) {
app := app.DeepCopy()
// use a one-off controller so other tests don't have a manual refresh request
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{}}, nil)
needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.False(t, needRefresh)
@@ -1682,7 +1680,7 @@ func TestNeedRefreshAppStatus(t *testing.T) {
}
// use a one-off controller so other tests don't have a manual refresh request
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{}}, nil)
needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour)
assert.False(t, needRefresh)
@@ -1762,7 +1760,7 @@ func TestNeedRefreshAppStatus(t *testing.T) {
}
func TestUpdatedManagedNamespaceMetadata(t *testing.T) {
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{}}, nil)
app := newFakeApp()
app.Spec.SyncPolicy.ManagedNamespaceMetadata = &v1alpha1.ManagedNamespaceMetadata{
Labels: map[string]string{
@@ -1786,7 +1784,7 @@ func TestUpdatedManagedNamespaceMetadata(t *testing.T) {
}
func TestUnchangedManagedNamespaceMetadata(t *testing.T) {
ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{}}, nil)
app := newFakeApp()
app.Spec.SyncPolicy.ManagedNamespaceMetadata = &v1alpha1.ManagedNamespaceMetadata{
Labels: map[string]string{
@@ -1829,7 +1827,7 @@ func TestRefreshAppConditions(t *testing.T) {
t.Run("NoErrorConditions", func(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app, &defaultProj}}, nil)
_, hasErrors := ctrl.refreshAppConditions(app)
assert.False(t, hasErrors)
@@ -1840,7 +1838,7 @@ func TestRefreshAppConditions(t *testing.T) {
app := newFakeApp()
app.Status.SetConditions([]v1alpha1.ApplicationCondition{{Type: v1alpha1.ApplicationConditionExcludedResourceWarning}}, nil)
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app, &defaultProj}}, nil)
_, hasErrors := ctrl.refreshAppConditions(app)
assert.False(t, hasErrors)
@@ -1853,7 +1851,7 @@ func TestRefreshAppConditions(t *testing.T) {
app.Spec.Project = "wrong project"
app.Status.SetConditions([]v1alpha1.ApplicationCondition{{Type: v1alpha1.ApplicationConditionInvalidSpecError, Message: "old message"}}, nil)
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app, &defaultProj}}, nil)
_, hasErrors := ctrl.refreshAppConditions(app)
assert.True(t, hasErrors)
@@ -1868,7 +1866,7 @@ func TestUpdateReconciledAt(t *testing.T) {
reconciledAt := metav1.NewTime(time.Now().Add(-1 * time.Second))
app.Status = v1alpha1.ApplicationStatus{ReconciledAt: &reconciledAt}
app.Status.Sync = v1alpha1.SyncStatus{ComparedTo: v1alpha1.ComparedTo{Source: app.Spec.GetSource(), Destination: app.Spec.Destination, IgnoreDifferences: app.Spec.IgnoreDifferences}}
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
@@ -1999,7 +1997,7 @@ apps/Deployment:
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{tc.app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
@@ -2063,7 +2061,7 @@ apps/Deployment:
return hs`,
}
ctrl := newFakeControllerWithResync(&fakeData{
ctrl := newFakeControllerWithResync(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
@@ -2130,7 +2128,7 @@ apps/Deployment:
func TestProjectErrorToCondition(t *testing.T) {
app := newFakeApp()
app.Spec.Project = "wrong project"
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
@@ -2158,7 +2156,7 @@ func TestProjectErrorToCondition(t *testing.T) {
func TestFinalizeProjectDeletion_HasApplications(t *testing.T) {
app := newFakeApp()
proj := &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, proj}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app, proj}}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
patched := false
@@ -2174,7 +2172,7 @@ func TestFinalizeProjectDeletion_HasApplications(t *testing.T) {
func TestFinalizeProjectDeletion_DoesNotHaveApplications(t *testing.T) {
proj := &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{&defaultProj}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{&defaultProj}}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]any{}
@@ -2200,7 +2198,7 @@ func TestProcessRequestedAppOperation_FailedNoRetries(t *testing.T) {
app.Operation = &v1alpha1.Operation{
Sync: &v1alpha1.SyncOperation{},
}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]any{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
@@ -2227,7 +2225,7 @@ func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) {
proj := defaultProj
proj.Name = "test-project"
proj.Spec.SourceNamespaces = []string{test.FakeArgoCDNamespace}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &proj}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app, &proj}}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]any{}
func() {
@@ -2256,7 +2254,7 @@ func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) {
Sync: &v1alpha1.SyncOperation{},
Retry: v1alpha1.RetryStrategy{Limit: 1},
}
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]any{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
@@ -2303,7 +2301,7 @@ func TestProcessRequestedAppOperation_RunningPreviouslyFailed(t *testing.T) {
Revision: "abc123",
},
}
ctrl := newFakeController(data, nil)
ctrl := newFakeController(t.Context(), data, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]any{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
@@ -2360,7 +2358,7 @@ func TestProcessRequestedAppOperation_RunningPreviouslyFailedBackoff(t *testing.
Revision: "abc123",
},
}
ctrl := newFakeController(data, nil)
ctrl := newFakeController(t.Context(), data, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
fakeAppCs.PrependReactor("patch", "*", func(_ kubetesting.Action) (handled bool, ret runtime.Object, err error) {
require.FailNow(t, "A patch should not have been called if the backoff has not passed")
@@ -2388,7 +2386,7 @@ func TestProcessRequestedAppOperation_HasRetriesTerminated(t *testing.T) {
Revision: "abc123",
},
}
ctrl := newFakeController(data, nil)
ctrl := newFakeController(t.Context(), data, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]any{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
@@ -2412,7 +2410,7 @@ func TestProcessRequestedAppOperation_Successful(t *testing.T) {
app.Operation = &v1alpha1.Operation{
Sync: &v1alpha1.SyncOperation{},
}
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponses: []*apiclient.ManifestResponse{{
Manifests: []string{},
@@ -2487,7 +2485,7 @@ func TestProcessRequestedAppOperation_SyncTimeout(t *testing.T) {
Revision: "HEAD",
},
}
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponses: []*apiclient.ManifestResponse{{
Manifests: []string{},
@@ -2529,9 +2527,9 @@ func TestGetAppHosts(t *testing.T) {
"application.allowedNodeLabels": "label1,label2",
},
}
ctrl := newFakeController(data, nil)
ctrl := newFakeController(t.Context(), data, nil)
mockStateCache := &mockstatecache.LiveStateCache{}
mockStateCache.On("IterateResources", mock.Anything, mock.MatchedBy(func(callback func(res *clustercache.Resource, info *statecache.ResourceInfo)) bool {
mockStateCache.EXPECT().IterateResources(mock.Anything, mock.MatchedBy(func(callback func(res *clustercache.Resource, info *statecache.ResourceInfo)) bool {
// node resource
callback(&clustercache.Resource{
Ref: corev1.ObjectReference{Name: "minikube", Kind: "Node", APIVersion: "v1"},
@@ -2557,7 +2555,7 @@ func TestGetAppHosts(t *testing.T) {
ResourceRequests: map[corev1.ResourceName]resource.Quantity{corev1.ResourceCPU: resource.MustParse("2")},
}})
return true
})).Return(nil)
})).Return(nil).Maybe()
ctrl.stateCache = mockStateCache
hosts, err := ctrl.getAppHosts(&v1alpha1.Cluster{Server: "test", Name: "test"}, app, []v1alpha1.ResourceNode{{
@@ -2584,15 +2582,15 @@ func TestGetAppHosts(t *testing.T) {
func TestMetricsExpiration(t *testing.T) {
app := newFakeApp()
// Check expiration is disabled by default
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
assert.False(t, ctrl.metricsServer.HasExpiration())
// Check expiration is enabled if set
ctrl = newFakeController(&fakeData{apps: []runtime.Object{app}, metricsCacheExpiration: 10 * time.Second}, nil)
ctrl = newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}, metricsCacheExpiration: 10 * time.Second}, nil)
assert.True(t, ctrl.metricsServer.HasExpiration())
}
func TestToAppKey(t *testing.T) {
ctrl := newFakeController(&fakeData{}, nil)
ctrl := newFakeController(t.Context(), &fakeData{}, nil)
tests := []struct {
name string
input string
@@ -2612,7 +2610,7 @@ func TestToAppKey(t *testing.T) {
func Test_canProcessApp(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
ctrl.applicationNamespaces = []string{"good"}
t.Run("without cluster filter, good namespace", func(t *testing.T) {
app.Namespace = "good"
@@ -2643,7 +2641,7 @@ func Test_canProcessAppSkipReconcileAnnotation(t *testing.T) {
appSkipReconcileFalse.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "false"}
appSkipReconcileTrue := newFakeApp()
appSkipReconcileTrue.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "true"}
ctrl := newFakeController(&fakeData{}, nil)
ctrl := newFakeController(t.Context(), &fakeData{}, nil)
tests := []struct {
name string
input any
@@ -2664,7 +2662,7 @@ func Test_canProcessAppSkipReconcileAnnotation(t *testing.T) {
func Test_syncDeleteOption(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil)
ctrl := newFakeController(t.Context(), &fakeData{apps: []runtime.Object{app}}, nil)
cm := newFakeCM()
t.Run("without delete option object is deleted", func(t *testing.T) {
cmObj := kube.MustToUnstructured(&cm)
@@ -2685,7 +2683,7 @@ func Test_syncDeleteOption(t *testing.T) {
func TestAddControllerNamespace(t *testing.T) {
t.Run("set controllerNamespace when the app is in the controller namespace", func(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{},
}, nil)
@@ -2703,7 +2701,7 @@ func TestAddControllerNamespace(t *testing.T) {
app.Namespace = appNamespace
proj := defaultProj
proj.Spec.SourceNamespaces = []string{appNamespace}
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &proj},
manifestResponse: &apiclient.ManifestResponse{},
applicationNamespaces: []string{appNamespace},
@@ -2960,7 +2958,7 @@ func assertDurationAround(t *testing.T, expected time.Duration, actual time.Dura
}
func TestSelfHealRemainingBackoff(t *testing.T) {
ctrl := newFakeController(&fakeData{}, nil)
ctrl := newFakeController(t.Context(), &fakeData{}, nil)
ctrl.selfHealBackoff = &wait.Backoff{
Factor: 3,
Duration: 2 * time.Second,
@@ -3042,7 +3040,7 @@ func TestSelfHealRemainingBackoff(t *testing.T) {
func TestSelfHealBackoffCooldownElapsed(t *testing.T) {
cooldown := time.Second * 30
ctrl := newFakeController(&fakeData{}, nil)
ctrl := newFakeController(t.Context(), &fakeData{}, nil)
ctrl.selfHealBackoffCooldown = cooldown
app := &v1alpha1.Application{

View File

@@ -40,7 +40,7 @@ func (n netError) Error() string { return string(n) }
func (n netError) Timeout() bool { return false }
func (n netError) Temporary() bool { return false }
func fixtures(data map[string]string, opts ...func(secret *corev1.Secret)) (*fake.Clientset, *argosettings.SettingsManager) {
func fixtures(ctx context.Context, data map[string]string, opts ...func(secret *corev1.Secret)) (*fake.Clientset, *argosettings.SettingsManager) {
cm := &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
@@ -65,17 +65,17 @@ func fixtures(data map[string]string, opts ...func(secret *corev1.Secret)) (*fak
opts[i](secret)
}
kubeClient := fake.NewClientset(cm, secret)
settingsManager := argosettings.NewSettingsManager(context.Background(), kubeClient, "default")
settingsManager := argosettings.NewSettingsManager(ctx, kubeClient, "default")
return kubeClient, settingsManager
}
func TestHandleModEvent_HasChanges(_ *testing.T) {
clusterCache := &mocks.ClusterCache{}
clusterCache.On("Invalidate", mock.Anything, mock.Anything).Return(nil).Once()
clusterCache.On("EnsureSynced").Return(nil).Once()
clusterCache.EXPECT().Invalidate(mock.Anything, mock.Anything).Return().Once()
clusterCache.EXPECT().EnsureSynced().Return(nil).Once()
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
db.EXPECT().GetApplicationControllerReplicas().Return(1)
clustersCache := liveStateCache{
clusters: map[string]cache.ClusterCache{
"https://mycluster": clusterCache,
@@ -95,10 +95,10 @@ func TestHandleModEvent_HasChanges(_ *testing.T) {
func TestHandleModEvent_ClusterExcluded(t *testing.T) {
clusterCache := &mocks.ClusterCache{}
clusterCache.On("Invalidate", mock.Anything, mock.Anything).Return(nil).Once()
clusterCache.On("EnsureSynced").Return(nil).Once()
clusterCache.EXPECT().Invalidate(mock.Anything, mock.Anything).Return().Once()
clusterCache.EXPECT().EnsureSynced().Return(nil).Once()
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
db.EXPECT().GetApplicationControllerReplicas().Return(1).Maybe()
clustersCache := liveStateCache{
db: nil,
appInformer: nil,
@@ -128,10 +128,10 @@ func TestHandleModEvent_ClusterExcluded(t *testing.T) {
func TestHandleModEvent_NoChanges(_ *testing.T) {
clusterCache := &mocks.ClusterCache{}
clusterCache.On("Invalidate", mock.Anything).Panic("should not invalidate")
clusterCache.On("EnsureSynced").Return(nil).Panic("should not re-sync")
clusterCache.EXPECT().Invalidate(mock.Anything).Panic("should not invalidate").Maybe()
clusterCache.EXPECT().EnsureSynced().Return(nil).Panic("should not re-sync").Maybe()
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
db.EXPECT().GetApplicationControllerReplicas().Return(1).Maybe()
clustersCache := liveStateCache{
clusters: map[string]cache.ClusterCache{
"https://mycluster": clusterCache,
@@ -150,7 +150,7 @@ func TestHandleModEvent_NoChanges(_ *testing.T) {
func TestHandleAddEvent_ClusterExcluded(t *testing.T) {
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
db.EXPECT().GetApplicationControllerReplicas().Return(1).Maybe()
clustersCache := liveStateCache{
clusters: map[string]cache.ClusterCache{},
clusterSharding: sharding.NewClusterSharding(db, 0, 2, common.DefaultShardingAlgorithm),
@@ -169,7 +169,7 @@ func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) {
Config: appv1.ClusterConfig{Username: "bar"},
}
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(1)
db.EXPECT().GetApplicationControllerReplicas().Return(1)
fakeClient := fake.NewClientset()
settingsMgr := argosettings.NewSettingsManager(t.Context(), fakeClient, "argocd")
gitopsEngineClusterCache := &mocks.ClusterCache{}
@@ -200,7 +200,7 @@ func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) {
handleDeleteWasCalled.Lock()
engineHoldsEngineLock.Lock()
gitopsEngineClusterCache.On("EnsureSynced").Run(func(_ mock.Arguments) {
gitopsEngineClusterCache.EXPECT().EnsureSynced().Run(func() {
gitopsEngineClusterCacheLock.Lock()
t.Log("EnsureSynced: Engine has engine lock")
engineHoldsEngineLock.Unlock()
@@ -214,7 +214,7 @@ func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) {
ensureSyncedCompleted.Unlock()
}).Return(nil).Once()
gitopsEngineClusterCache.On("Invalidate").Run(func(_ mock.Arguments) {
gitopsEngineClusterCache.EXPECT().Invalidate().Run(func(_ ...cache.UpdateSettingsFunc) {
// Allow EnsureSynced to continue now that we're in the deadlock condition
handleDeleteWasCalled.Unlock()
// Wait until gitops engine holds the gitops lock
@@ -227,7 +227,7 @@ func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) {
t.Log("Invalidate: Invalidate has engine lock")
gitopsEngineClusterCacheLock.Unlock()
invalidateCompleted.Unlock()
}).Return()
}).Return().Maybe()
go func() {
// Start the gitops-engine lock holds
go func() {
@@ -775,7 +775,7 @@ func Test_GetVersionsInfo_error_redacted(t *testing.T) {
}
func TestLoadCacheSettings(t *testing.T) {
_, settingsManager := fixtures(map[string]string{
_, settingsManager := fixtures(t.Context(), map[string]string{
"application.instanceLabelKey": "testLabel",
"application.resourceTrackingMethod": string(appv1.TrackingMethodLabel),
"installationID": "123456789",

View File

@@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -124,7 +125,7 @@ func Test_getAppsForHydrationKey_RepoURLNormalization(t *testing.T) {
t.Parallel()
d := mocks.NewDependencies(t)
d.On("GetProcessableApps").Return(&v1alpha1.ApplicationList{
d.EXPECT().GetProcessableApps().Return(&v1alpha1.ApplicationList{
Items: []v1alpha1.Application{
{
Spec: v1alpha1.ApplicationSpec{
@@ -276,7 +277,7 @@ func Test_validateApplications_RootPathSkipped(t *testing.T) {
},
}
d.On("GetProcessableAppProj", mock.Anything).Return(&v1alpha1.AppProject{
d.EXPECT().GetProcessableAppProj(mock.Anything).Return(&v1alpha1.AppProject{
Spec: v1alpha1.AppProjectSpec{
SourceRepos: []string{"https://example.com/*"},
},
@@ -394,10 +395,10 @@ func TestProcessAppHydrateQueueItem_HydrationNeeded(t *testing.T) {
app.Status.SourceHydrator.CurrentOperation = nil
var persistedStatus *v1alpha1.SourceHydratorStatus
d.On("PersistAppHydratorStatus", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
persistedStatus = args.Get(1).(*v1alpha1.SourceHydratorStatus)
d.EXPECT().PersistAppHydratorStatus(mock.Anything, mock.Anything).Run(func(_ *v1alpha1.Application, newStatus *v1alpha1.SourceHydratorStatus) {
persistedStatus = newStatus
}).Return().Once()
d.On("AddHydrationQueueItem", mock.Anything).Return().Once()
d.EXPECT().AddHydrationQueueItem(mock.Anything).Return().Once()
h := &Hydrator{
dependencies: d,
@@ -432,7 +433,7 @@ func TestProcessAppHydrateQueueItem_HydrationPassedTimeout(t *testing.T) {
},
},
}
d.On("AddHydrationQueueItem", mock.Anything).Return().Once()
d.EXPECT().AddHydrationQueueItem(mock.Anything).Return().Once()
h := &Hydrator{
dependencies: d,
@@ -495,20 +496,21 @@ func TestProcessHydrationQueueItem_ValidationFails(t *testing.T) {
hydrationKey := getHydrationQueueKey(app1)
// getAppsForHydrationKey returns two apps
d.On("GetProcessableApps").Return(&v1alpha1.ApplicationList{Items: []v1alpha1.Application{*app1, *app2}}, nil)
d.On("GetProcessableAppProj", mock.Anything).Return(nil, errors.New("test error")).Once()
d.On("GetProcessableAppProj", mock.Anything).Return(newTestProject(), nil).Once()
d.EXPECT().GetProcessableApps().Return(&v1alpha1.ApplicationList{Items: []v1alpha1.Application{*app1, *app2}}, nil)
d.EXPECT().GetProcessableAppProj(mock.Anything).Return(nil, errors.New("test error")).Once()
d.EXPECT().GetProcessableAppProj(mock.Anything).Return(newTestProject(), nil).Once()
h := &Hydrator{dependencies: d}
// Expect setAppHydratorError to be called
var persistedStatus1 *v1alpha1.SourceHydratorStatus
var persistedStatus2 *v1alpha1.SourceHydratorStatus
d.On("PersistAppHydratorStatus", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
if args.Get(0).(*v1alpha1.Application).Name == app1.Name {
persistedStatus1 = args.Get(1).(*v1alpha1.SourceHydratorStatus)
} else if args.Get(0).(*v1alpha1.Application).Name == app2.Name {
persistedStatus2 = args.Get(1).(*v1alpha1.SourceHydratorStatus)
d.EXPECT().PersistAppHydratorStatus(mock.Anything, mock.Anything).Run(func(orig *v1alpha1.Application, newStatus *v1alpha1.SourceHydratorStatus) {
switch orig.Name {
case app1.Name:
persistedStatus1 = newStatus
case app2.Name:
persistedStatus2 = newStatus
}
}).Return().Twice()
@@ -536,22 +538,23 @@ func TestProcessHydrationQueueItem_HydrateFails_AppSpecificError(t *testing.T) {
app2 = setTestAppPhase(app2, v1alpha1.HydrateOperationPhaseHydrating)
hydrationKey := getHydrationQueueKey(app1)
d.On("GetProcessableApps").Return(&v1alpha1.ApplicationList{Items: []v1alpha1.Application{*app1, *app2}}, nil)
d.On("GetProcessableAppProj", mock.Anything).Return(newTestProject(), nil)
d.EXPECT().GetProcessableApps().Return(&v1alpha1.ApplicationList{Items: []v1alpha1.Application{*app1, *app2}}, nil)
d.EXPECT().GetProcessableAppProj(mock.Anything).Return(newTestProject(), nil)
h := &Hydrator{dependencies: d}
// Make hydrate return app-specific error
d.On("GetRepoObjs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, errors.New("hydrate error"))
d.EXPECT().GetRepoObjs(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, errors.New("hydrate error"))
// Expect setAppHydratorError to be called
var persistedStatus1 *v1alpha1.SourceHydratorStatus
var persistedStatus2 *v1alpha1.SourceHydratorStatus
d.On("PersistAppHydratorStatus", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
if args.Get(0).(*v1alpha1.Application).Name == app1.Name {
persistedStatus1 = args.Get(1).(*v1alpha1.SourceHydratorStatus)
} else if args.Get(0).(*v1alpha1.Application).Name == app2.Name {
persistedStatus2 = args.Get(1).(*v1alpha1.SourceHydratorStatus)
d.EXPECT().PersistAppHydratorStatus(mock.Anything, mock.Anything).Run(func(orig *v1alpha1.Application, newStatus *v1alpha1.SourceHydratorStatus) {
switch orig.Name {
case app1.Name:
persistedStatus1 = newStatus
case app2.Name:
persistedStatus2 = newStatus
}
}).Return().Twice()
@@ -579,23 +582,24 @@ func TestProcessHydrationQueueItem_HydrateFails_CommonError(t *testing.T) {
app2.Spec.SourceHydrator.SyncSource.Path = "something/else"
app2 = setTestAppPhase(app2, v1alpha1.HydrateOperationPhaseHydrating)
hydrationKey := getHydrationQueueKey(app1)
d.On("GetProcessableApps").Return(&v1alpha1.ApplicationList{Items: []v1alpha1.Application{*app1, *app2}}, nil)
d.On("GetProcessableAppProj", mock.Anything).Return(newTestProject(), nil)
d.EXPECT().GetProcessableApps().Return(&v1alpha1.ApplicationList{Items: []v1alpha1.Application{*app1, *app2}}, nil)
d.EXPECT().GetProcessableAppProj(mock.Anything).Return(newTestProject(), nil)
h := &Hydrator{dependencies: d, repoGetter: r}
d.On("GetRepoObjs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, &repoclient.ManifestResponse{
d.EXPECT().GetRepoObjs(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, &repoclient.ManifestResponse{
Revision: "abc123",
}, nil)
r.On("GetRepository", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("repo error"))
r.EXPECT().GetRepository(mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("repo error"))
// Expect setAppHydratorError to be called
var persistedStatus1 *v1alpha1.SourceHydratorStatus
var persistedStatus2 *v1alpha1.SourceHydratorStatus
d.On("PersistAppHydratorStatus", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
if args.Get(0).(*v1alpha1.Application).Name == app1.Name {
persistedStatus1 = args.Get(1).(*v1alpha1.SourceHydratorStatus)
} else if args.Get(0).(*v1alpha1.Application).Name == app2.Name {
persistedStatus2 = args.Get(1).(*v1alpha1.SourceHydratorStatus)
d.EXPECT().PersistAppHydratorStatus(mock.Anything, mock.Anything).Run(func(orig *v1alpha1.Application, newStatus *v1alpha1.SourceHydratorStatus) {
switch orig.Name {
case app1.Name:
persistedStatus1 = newStatus
case app2.Name:
persistedStatus2 = newStatus
}
}).Return().Twice()
@@ -624,24 +628,24 @@ func TestProcessHydrationQueueItem_SuccessfulHydration(t *testing.T) {
cc := commitservermocks.NewCommitServiceClient(t)
app := setTestAppPhase(newTestApp("test-app"), v1alpha1.HydrateOperationPhaseHydrating)
hydrationKey := getHydrationQueueKey(app)
d.On("GetProcessableApps").Return(&v1alpha1.ApplicationList{Items: []v1alpha1.Application{*app}}, nil)
d.On("GetProcessableAppProj", mock.Anything).Return(newTestProject(), nil)
d.EXPECT().GetProcessableApps().Return(&v1alpha1.ApplicationList{Items: []v1alpha1.Application{*app}}, nil)
d.EXPECT().GetProcessableAppProj(mock.Anything).Return(newTestProject(), nil)
h := &Hydrator{dependencies: d, repoGetter: r, commitClientset: &commitservermocks.Clientset{CommitServiceClient: cc}, repoClientset: &reposervermocks.Clientset{RepoServerServiceClient: rc}}
// Expect setAppHydratorError to be called
var persistedStatus *v1alpha1.SourceHydratorStatus
d.On("PersistAppHydratorStatus", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
persistedStatus = args.Get(1).(*v1alpha1.SourceHydratorStatus)
d.EXPECT().PersistAppHydratorStatus(mock.Anything, mock.Anything).Run(func(_ *v1alpha1.Application, newStatus *v1alpha1.SourceHydratorStatus) {
persistedStatus = newStatus
}).Return().Once()
d.On("RequestAppRefresh", app.Name, app.Namespace).Return(nil).Once()
d.On("GetRepoObjs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, &repoclient.ManifestResponse{
d.EXPECT().RequestAppRefresh(app.Name, app.Namespace).Return(nil).Once()
d.EXPECT().GetRepoObjs(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, &repoclient.ManifestResponse{
Revision: "abc123",
}, nil).Once()
r.On("GetRepository", mock.Anything, "https://example.com/repo", "test-project").Return(nil, nil).Once()
rc.On("GetRevisionMetadata", mock.Anything, mock.Anything).Return(nil, nil).Once()
d.On("GetWriteCredentials", mock.Anything, "https://example.com/repo", "test-project").Return(nil, nil).Once()
d.On("GetHydratorCommitMessageTemplate").Return("commit message", nil).Once()
cc.On("CommitHydratedManifests", mock.Anything, mock.Anything).Return(&commitclient.CommitHydratedManifestsResponse{HydratedSha: "def456"}, nil).Once()
r.EXPECT().GetRepository(mock.Anything, "https://example.com/repo", "test-project").Return(nil, nil).Once()
rc.EXPECT().GetRevisionMetadata(mock.Anything, mock.Anything).Return(nil, nil).Once()
d.EXPECT().GetWriteCredentials(mock.Anything, "https://example.com/repo", "test-project").Return(nil, nil).Once()
d.EXPECT().GetHydratorCommitMessageTemplate().Return("commit message", nil).Once()
cc.EXPECT().CommitHydratedManifests(mock.Anything, mock.Anything).Return(&commitclient.CommitHydratedManifestsResponse{HydratedSha: "def456"}, nil).Once()
h.ProcessHydrationQueueItem(hydrationKey)
@@ -665,7 +669,7 @@ func TestValidateApplications_ProjectError(t *testing.T) {
t.Parallel()
d := mocks.NewDependencies(t)
app := newTestApp("test-app")
d.On("GetProcessableAppProj", app).Return(nil, errors.New("project error")).Once()
d.EXPECT().GetProcessableAppProj(app).Return(nil, errors.New("project error")).Once()
h := &Hydrator{dependencies: d}
projects, errs := h.validateApplications([]*v1alpha1.Application{app})
@@ -680,7 +684,7 @@ func TestValidateApplications_SourceNotPermitted(t *testing.T) {
app := newTestApp("test-app")
proj := newTestProject()
proj.Spec.SourceRepos = []string{"not-allowed"}
d.On("GetProcessableAppProj", app).Return(proj, nil).Once()
d.EXPECT().GetProcessableAppProj(app).Return(proj, nil).Once()
h := &Hydrator{dependencies: d}
projects, errs := h.validateApplications([]*v1alpha1.Application{app})
@@ -695,7 +699,7 @@ func TestValidateApplications_RootPath(t *testing.T) {
app := newTestApp("test-app")
app.Spec.SourceHydrator.SyncSource.Path = "."
proj := newTestProject()
d.On("GetProcessableAppProj", app).Return(proj, nil).Once()
d.EXPECT().GetProcessableAppProj(app).Return(proj, nil).Once()
h := &Hydrator{dependencies: d}
projects, errs := h.validateApplications([]*v1alpha1.Application{app})
@@ -711,8 +715,8 @@ func TestValidateApplications_DuplicateDestination(t *testing.T) {
app2 := newTestApp("app2")
app2.Spec.SourceHydrator.SyncSource.Path = app1.Spec.SourceHydrator.SyncSource.Path // duplicate path
proj := newTestProject()
d.On("GetProcessableAppProj", app1).Return(proj, nil).Once()
d.On("GetProcessableAppProj", app2).Return(proj, nil).Once()
d.EXPECT().GetProcessableAppProj(app1).Return(proj, nil).Once()
d.EXPECT().GetProcessableAppProj(app2).Return(proj, nil).Once()
h := &Hydrator{dependencies: d}
projects, errs := h.validateApplications([]*v1alpha1.Application{app1, app2})
@@ -729,8 +733,8 @@ func TestValidateApplications_Success(t *testing.T) {
app2 := newTestApp("app2")
app2.Spec.SourceHydrator.SyncSource.Path = "other-path"
proj := newTestProject()
d.On("GetProcessableAppProj", app1).Return(proj, nil).Once()
d.On("GetProcessableAppProj", app2).Return(proj, nil).Once()
d.EXPECT().GetProcessableAppProj(app1).Return(proj, nil).Once()
d.EXPECT().GetProcessableAppProj(app2).Return(proj, nil).Once()
h := &Hydrator{dependencies: d}
projects, errs := h.validateApplications([]*v1alpha1.Application{app1, app2})
@@ -791,27 +795,25 @@ func TestHydrator_hydrate_Success(t *testing.T) {
readRepo := &v1alpha1.Repository{Repo: "https://example.com/repo"}
writeRepo := &v1alpha1.Repository{Repo: "https://example.com/repo"}
d.On("GetRepoObjs", mock.Anything, app1, app1.Spec.SourceHydrator.GetDrySource(), "main", proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
d.On("GetRepoObjs", mock.Anything, app2, app2.Spec.SourceHydrator.GetDrySource(), "sha123", proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.On("GetRepository", mock.Anything, readRepo.Repo, proj.Name).Return(readRepo, nil)
rc.On("GetRevisionMetadata", mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{Message: "metadata"}, nil).Run(func(args mock.Arguments) {
r := args.Get(1).(*repoclient.RepoServerRevisionMetadataRequest)
assert.Equal(t, readRepo, r.Repo)
assert.Equal(t, "sha123", r.Revision)
d.EXPECT().GetRepoObjs(mock.Anything, app1, app1.Spec.SourceHydrator.GetDrySource(), "main", proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
d.EXPECT().GetRepoObjs(mock.Anything, app2, app2.Spec.SourceHydrator.GetDrySource(), "sha123", proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.EXPECT().GetRepository(mock.Anything, readRepo.Repo, proj.Name).Return(readRepo, nil)
rc.EXPECT().GetRevisionMetadata(mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{Message: "metadata"}, nil).Run(func(_ context.Context, in *repoclient.RepoServerRevisionMetadataRequest, _ ...grpc.CallOption) {
assert.Equal(t, readRepo, in.Repo)
assert.Equal(t, "sha123", in.Revision)
})
d.On("GetWriteCredentials", mock.Anything, readRepo.Repo, proj.Name).Return(writeRepo, nil)
d.On("GetHydratorCommitMessageTemplate").Return("commit message", nil)
cc.On("CommitHydratedManifests", mock.Anything, mock.Anything).Return(&commitclient.CommitHydratedManifestsResponse{HydratedSha: "hydrated123"}, nil).Run(func(args mock.Arguments) {
r := args.Get(1).(*commitclient.CommitHydratedManifestsRequest)
assert.Equal(t, "commit message", r.CommitMessage)
assert.Equal(t, "hydrated", r.SyncBranch)
assert.Equal(t, "hydrated-next", r.TargetBranch)
assert.Equal(t, "sha123", r.DrySha)
assert.Equal(t, writeRepo, r.Repo)
assert.Len(t, r.Paths, 2)
assert.Equal(t, app1.Spec.SourceHydrator.SyncSource.Path, r.Paths[0].Path)
assert.Equal(t, app2.Spec.SourceHydrator.SyncSource.Path, r.Paths[1].Path)
assert.Equal(t, "metadata", r.DryCommitMetadata.Message)
d.EXPECT().GetWriteCredentials(mock.Anything, readRepo.Repo, proj.Name).Return(writeRepo, nil)
d.EXPECT().GetHydratorCommitMessageTemplate().Return("commit message", nil)
cc.EXPECT().CommitHydratedManifests(mock.Anything, mock.Anything).Return(&commitclient.CommitHydratedManifestsResponse{HydratedSha: "hydrated123"}, nil).Run(func(_ context.Context, in *commitclient.CommitHydratedManifestsRequest, _ ...grpc.CallOption) {
assert.Equal(t, "commit message", in.CommitMessage)
assert.Equal(t, "hydrated", in.SyncBranch)
assert.Equal(t, "hydrated-next", in.TargetBranch)
assert.Equal(t, "sha123", in.DrySha)
assert.Equal(t, writeRepo, in.Repo)
assert.Len(t, in.Paths, 2)
assert.Equal(t, app1.Spec.SourceHydrator.SyncSource.Path, in.Paths[0].Path)
assert.Equal(t, app2.Spec.SourceHydrator.SyncSource.Path, in.Paths[1].Path)
assert.Equal(t, "metadata", in.DryCommitMetadata.Message)
})
logCtx := log.NewEntry(log.StandardLogger())
@@ -841,7 +843,7 @@ func TestHydrator_hydrate_GetManifestsError(t *testing.T) {
proj := newTestProject()
projects := map[string]*v1alpha1.AppProject{app.Spec.Project: proj}
d.On("GetRepoObjs", mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, nil, errors.New("manifests error"))
d.EXPECT().GetRepoObjs(mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, nil, errors.New("manifests error"))
logCtx := log.NewEntry(log.StandardLogger())
sha, hydratedSha, errs, err := h.hydrate(logCtx, []*v1alpha1.Application{app}, projects)
@@ -871,9 +873,9 @@ func TestHydrator_hydrate_RevisionMetadataError(t *testing.T) {
proj := newTestProject()
projects := map[string]*v1alpha1.AppProject{app.Spec.Project: proj}
d.On("GetRepoObjs", mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.On("GetRepository", mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.On("GetRevisionMetadata", mock.Anything, mock.Anything).Return(nil, errors.New("metadata error"))
d.EXPECT().GetRepoObjs(mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.EXPECT().GetRepository(mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.EXPECT().GetRevisionMetadata(mock.Anything, mock.Anything).Return(nil, errors.New("metadata error"))
logCtx := log.NewEntry(log.StandardLogger())
sha, hydratedSha, errs, err := h.hydrate(logCtx, []*v1alpha1.Application{app}, projects)
@@ -903,10 +905,10 @@ func TestHydrator_hydrate_GetWriteCredentialsError(t *testing.T) {
proj := newTestProject()
projects := map[string]*v1alpha1.AppProject{app.Spec.Project: proj}
d.On("GetRepoObjs", mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.On("GetRepository", mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.On("GetRevisionMetadata", mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{}, nil)
d.On("GetWriteCredentials", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("creds error"))
d.EXPECT().GetRepoObjs(mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.EXPECT().GetRepository(mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.EXPECT().GetRevisionMetadata(mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{}, nil)
d.EXPECT().GetWriteCredentials(mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("creds error"))
logCtx := log.NewEntry(log.StandardLogger())
sha, hydratedSha, errs, err := h.hydrate(logCtx, []*v1alpha1.Application{app}, projects)
@@ -936,11 +938,11 @@ func TestHydrator_hydrate_CommitMessageTemplateError(t *testing.T) {
proj := newTestProject()
projects := map[string]*v1alpha1.AppProject{app.Spec.Project: proj}
d.On("GetRepoObjs", mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.On("GetRepository", mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.On("GetRevisionMetadata", mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{}, nil)
d.On("GetWriteCredentials", mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
d.On("GetHydratorCommitMessageTemplate").Return("", errors.New("template error"))
d.EXPECT().GetRepoObjs(mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.EXPECT().GetRepository(mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.EXPECT().GetRevisionMetadata(mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{}, nil)
d.EXPECT().GetWriteCredentials(mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
d.EXPECT().GetHydratorCommitMessageTemplate().Return("", errors.New("template error"))
logCtx := log.NewEntry(log.StandardLogger())
sha, hydratedSha, errs, err := h.hydrate(logCtx, []*v1alpha1.Application{app}, projects)
@@ -970,11 +972,11 @@ func TestHydrator_hydrate_TemplatedCommitMessageError(t *testing.T) {
proj := newTestProject()
projects := map[string]*v1alpha1.AppProject{app.Spec.Project: proj}
d.On("GetRepoObjs", mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.On("GetRepository", mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.On("GetRevisionMetadata", mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{}, nil)
d.On("GetWriteCredentials", mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
d.On("GetHydratorCommitMessageTemplate").Return("{{ notAFunction }} template", nil)
d.EXPECT().GetRepoObjs(mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.EXPECT().GetRepository(mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.EXPECT().GetRevisionMetadata(mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{}, nil)
d.EXPECT().GetWriteCredentials(mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
d.EXPECT().GetHydratorCommitMessageTemplate().Return("{{ notAFunction }} template", nil)
logCtx := log.NewEntry(log.StandardLogger())
sha, hydratedSha, errs, err := h.hydrate(logCtx, []*v1alpha1.Application{app}, projects)
@@ -1004,12 +1006,12 @@ func TestHydrator_hydrate_CommitHydratedManifestsError(t *testing.T) {
proj := newTestProject()
projects := map[string]*v1alpha1.AppProject{app.Spec.Project: proj}
d.On("GetRepoObjs", mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.On("GetRepository", mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.On("GetRevisionMetadata", mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{}, nil)
d.On("GetWriteCredentials", mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
d.On("GetHydratorCommitMessageTemplate").Return("commit message", nil)
cc.On("CommitHydratedManifests", mock.Anything, mock.Anything).Return(nil, errors.New("commit error"))
d.EXPECT().GetRepoObjs(mock.Anything, app, mock.Anything, mock.Anything, proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
r.EXPECT().GetRepository(mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
rc.EXPECT().GetRevisionMetadata(mock.Anything, mock.Anything).Return(&v1alpha1.RevisionMetadata{}, nil)
d.EXPECT().GetWriteCredentials(mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.Repository{Repo: "https://example.com/repo"}, nil)
d.EXPECT().GetHydratorCommitMessageTemplate().Return("commit message", nil)
cc.EXPECT().CommitHydratedManifests(mock.Anything, mock.Anything).Return(nil, errors.New("commit error"))
logCtx := log.NewEntry(log.StandardLogger())
sha, hydratedSha, errs, err := h.hydrate(logCtx, []*v1alpha1.Application{app}, projects)
@@ -1048,12 +1050,12 @@ func TestHydrator_getManifests_Success(t *testing.T) {
},
})
d.On("GetRepoObjs", mock.Anything, app, app.Spec.SourceHydrator.GetDrySource(), "sha123", proj).Return([]*unstructured.Unstructured{cm}, &repoclient.ManifestResponse{
d.EXPECT().GetRepoObjs(mock.Anything, app, app.Spec.SourceHydrator.GetDrySource(), "sha123", proj).Return([]*unstructured.Unstructured{cm}, &repoclient.ManifestResponse{
Revision: "sha123",
Commands: []string{"cmd1", "cmd2"},
}, nil)
rev, pathDetails, err := h.getManifests(context.Background(), app, "sha123", proj)
rev, pathDetails, err := h.getManifests(t.Context(), app, "sha123", proj)
require.NoError(t, err)
assert.Equal(t, "sha123", rev)
assert.Equal(t, app.Spec.SourceHydrator.SyncSource.Path, pathDetails.Path)
@@ -1069,9 +1071,9 @@ func TestHydrator_getManifests_EmptyTargetRevision(t *testing.T) {
app := newTestApp("test-app")
proj := newTestProject()
d.On("GetRepoObjs", mock.Anything, app, mock.Anything, "main", proj).Return([]*unstructured.Unstructured{}, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
d.EXPECT().GetRepoObjs(mock.Anything, app, mock.Anything, "main", proj).Return([]*unstructured.Unstructured{}, &repoclient.ManifestResponse{Revision: "sha123"}, nil)
rev, pathDetails, err := h.getManifests(context.Background(), app, "", proj)
rev, pathDetails, err := h.getManifests(t.Context(), app, "", proj)
require.NoError(t, err)
assert.Equal(t, "sha123", rev)
assert.NotNil(t, pathDetails)
@@ -1084,9 +1086,9 @@ func TestHydrator_getManifests_GetRepoObjsError(t *testing.T) {
app := newTestApp("test-app")
proj := newTestProject()
d.On("GetRepoObjs", mock.Anything, app, mock.Anything, "main", proj).Return(nil, nil, errors.New("repo error"))
d.EXPECT().GetRepoObjs(mock.Anything, app, mock.Anything, "main", proj).Return(nil, nil, errors.New("repo error"))
rev, pathDetails, err := h.getManifests(context.Background(), app, "main", proj)
rev, pathDetails, err := h.getManifests(t.Context(), app, "main", proj)
require.Error(t, err)
assert.Contains(t, err.Error(), "repo error")
assert.Empty(t, rev)

View File

@@ -43,7 +43,7 @@ func TestGetRepoObjs(t *testing.T) {
},
}
ctrl := newFakeControllerWithResync(&data, time.Minute, nil, errors.New("this should not be called"))
ctrl := newFakeControllerWithResync(t.Context(), &data, time.Minute, nil, errors.New("this should not be called"))
source := app.Spec.GetSource()
source.RepoURL = "oci://example.com/argo/argo-cd"
@@ -92,7 +92,7 @@ func TestGetHydratorCommitMessageTemplate_WhenTemplateisNotDefined_FallbackToDef
},
}
ctrl := newFakeControllerWithResync(&data, time.Minute, nil, errors.New("this should not be called"))
ctrl := newFakeControllerWithResync(t.Context(), &data, time.Minute, nil, errors.New("this should not be called"))
tmpl, err := ctrl.GetHydratorCommitMessageTemplate()
require.NoError(t, err)
@@ -115,7 +115,7 @@ func TestGetHydratorCommitMessageTemplate(t *testing.T) {
configMapData: cm.Data,
}
ctrl := newFakeControllerWithResync(&data, time.Minute, nil, errors.New("this should not be called"))
ctrl := newFakeControllerWithResync(t.Context(), &data, time.Minute, nil, errors.New("this should not be called"))
tmpl, err := ctrl.GetHydratorCommitMessageTemplate()
require.NoError(t, err)

View File

@@ -13,12 +13,12 @@ import (
)
func TestMetricClusterConnectivity(t *testing.T) {
db := dbmocks.ArgoDB{}
db := &dbmocks.ArgoDB{}
cluster1 := v1alpha1.Cluster{Name: "cluster1", Server: "server1", Labels: map[string]string{"env": "dev", "team": "team1"}}
cluster2 := v1alpha1.Cluster{Name: "cluster2", Server: "server2", Labels: map[string]string{"env": "staging", "team": "team2"}}
cluster3 := v1alpha1.Cluster{Name: "cluster3", Server: "server3", Labels: map[string]string{"env": "production", "team": "team3"}}
clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{cluster1, cluster2, cluster3}}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
db.EXPECT().ListClusters(mock.Anything).Return(clusterList, nil)
type testCases struct {
testCombination

View File

@@ -263,8 +263,8 @@ func newFakeApp(fakeAppYAML string) *argoappv1.Application {
return &app
}
func newFakeLister(fakeAppYAMLs ...string) (context.CancelFunc, applister.ApplicationLister) {
ctx, cancel := context.WithCancel(context.Background())
func newFakeLister(ctx context.Context, fakeAppYAMLs ...string) (context.CancelFunc, applister.ApplicationLister) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
var fakeApps []runtime.Object
for _, appYAML := range fakeAppYAMLs {
@@ -319,11 +319,11 @@ func testMetricServer(t *testing.T, fakeAppYAMLs []string, expectedResponse stri
func runTest(t *testing.T, cfg TestMetricServerConfig) {
t.Helper()
cancel, appLister := newFakeLister(cfg.FakeAppYAMLs...)
cancel, appLister := newFakeLister(t.Context(), cfg.FakeAppYAMLs...)
defer cancel()
mockDB := mocks.NewArgoDB(t)
mockDB.On("GetClusterServersByName", mock.Anything, "cluster1").Return([]string{"https://localhost:6443"}, nil)
mockDB.On("GetCluster", mock.Anything, "https://localhost:6443").Return(&argoappv1.Cluster{Name: "cluster1", Server: "https://localhost:6443"}, nil)
mockDB.EXPECT().GetClusterServersByName(mock.Anything, "cluster1").Return([]string{"https://localhost:6443"}, nil).Maybe()
mockDB.EXPECT().GetCluster(mock.Anything, "https://localhost:6443").Return(&argoappv1.Cluster{Name: "cluster1", Server: "https://localhost:6443"}, nil).Maybe()
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, cfg.AppLabels, cfg.AppConditions, mockDB)
require.NoError(t, err)
@@ -472,7 +472,7 @@ argocd_app_condition{condition="ExcludedResourceWarning",name="my-app-4",namespa
}
func TestMetricsSyncCounter(t *testing.T) {
cancel, appLister := newFakeLister()
cancel, appLister := newFakeLister(t.Context())
defer cancel()
mockDB := mocks.NewArgoDB(t)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{}, []string{}, mockDB)
@@ -526,7 +526,7 @@ func assertMetricsNotPrinted(t *testing.T, expectedLines, body string) {
}
func TestMetricsSyncDuration(t *testing.T) {
cancel, appLister := newFakeLister()
cancel, appLister := newFakeLister(t.Context())
defer cancel()
mockDB := mocks.NewArgoDB(t)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{}, []string{}, mockDB)
@@ -567,7 +567,7 @@ argocd_app_sync_duration_seconds_total{dest_server="https://localhost:6443",name
}
func TestReconcileMetrics(t *testing.T) {
cancel, appLister := newFakeLister()
cancel, appLister := newFakeLister(t.Context())
defer cancel()
mockDB := mocks.NewArgoDB(t)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{}, []string{}, mockDB)
@@ -601,7 +601,7 @@ argocd_app_reconcile_count{dest_server="https://localhost:6443",namespace="argoc
}
func TestOrphanedResourcesMetric(t *testing.T) {
cancel, appLister := newFakeLister()
cancel, appLister := newFakeLister(t.Context())
defer cancel()
mockDB := mocks.NewArgoDB(t)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{}, []string{}, mockDB)
@@ -627,7 +627,7 @@ argocd_app_orphaned_resources_count{name="my-app-4",namespace="argocd",project="
}
func TestMetricsReset(t *testing.T) {
cancel, appLister := newFakeLister()
cancel, appLister := newFakeLister(t.Context())
defer cancel()
mockDB := mocks.NewArgoDB(t)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{}, []string{}, mockDB)
@@ -665,7 +665,7 @@ argocd_app_sync_total{dest_server="https://localhost:6443",dry_run="false",name=
}
func TestWorkqueueMetrics(t *testing.T) {
cancel, appLister := newFakeLister()
cancel, appLister := newFakeLister(t.Context())
defer cancel()
mockDB := mocks.NewArgoDB(t)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{}, []string{}, mockDB)
@@ -696,7 +696,7 @@ workqueue_unfinished_work_seconds{controller="test",name="test"}
}
func TestGoMetrics(t *testing.T) {
cancel, appLister := newFakeLister()
cancel, appLister := newFakeLister(t.Context())
defer cancel()
mockDB := mocks.NewArgoDB(t)
metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{}, []string{}, mockDB)

View File

@@ -28,7 +28,7 @@ import (
func TestGetShardByID_NotEmptyID(t *testing.T) {
db := &dbmocks.ArgoDB{}
replicasCount := 1
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Maybe()
assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "1"}))
assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "2"}))
assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "3"}))
@@ -38,7 +38,7 @@ func TestGetShardByID_NotEmptyID(t *testing.T) {
func TestGetShardByID_EmptyID(t *testing.T) {
db := &dbmocks.ArgoDB{}
replicasCount := 1
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Maybe()
distributionFunction := LegacyDistributionFunction
shard := distributionFunction(replicasCount)(&v1alpha1.Cluster{})
assert.Equal(t, 0, shard)
@@ -46,7 +46,7 @@ func TestGetShardByID_EmptyID(t *testing.T) {
func TestGetShardByID_NoReplicas(t *testing.T) {
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(0)
db.EXPECT().GetApplicationControllerReplicas().Return(0).Maybe()
distributionFunction := LegacyDistributionFunction
shard := distributionFunction(0)(&v1alpha1.Cluster{})
assert.Equal(t, -1, shard)
@@ -54,7 +54,7 @@ func TestGetShardByID_NoReplicas(t *testing.T) {
func TestGetShardByID_NoReplicasUsingHashDistributionFunction(t *testing.T) {
db := &dbmocks.ArgoDB{}
db.On("GetApplicationControllerReplicas").Return(0)
db.EXPECT().GetApplicationControllerReplicas().Return(0).Maybe()
distributionFunction := LegacyDistributionFunction
shard := distributionFunction(0)(&v1alpha1.Cluster{})
assert.Equal(t, -1, shard)
@@ -63,7 +63,7 @@ func TestGetShardByID_NoReplicasUsingHashDistributionFunction(t *testing.T) {
func TestGetShardByID_NoReplicasUsingHashDistributionFunctionWithClusters(t *testing.T) {
clusters, db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters()
// Test with replicas set to 0
db.On("GetApplicationControllerReplicas").Return(0)
db.EXPECT().GetApplicationControllerReplicas().Return(0).Maybe()
t.Setenv(common.EnvControllerShardingAlgorithm, common.RoundRobinShardingAlgorithm)
distributionFunction := RoundRobinDistributionFunction(clusters, 0)
assert.Equal(t, -1, distributionFunction(nil))
@@ -91,7 +91,7 @@ func TestGetClusterFilterLegacy(t *testing.T) {
// shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...)
clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Maybe()
t.Setenv(common.EnvControllerShardingAlgorithm, common.LegacyShardingAlgorithm)
distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
@@ -109,7 +109,7 @@ func TestGetClusterFilterUnknown(t *testing.T) {
os.Unsetenv(common.EnvControllerShardingAlgorithm)
t.Setenv(common.EnvControllerShardingAlgorithm, "unknown")
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Maybe()
distributionFunction := GetDistributionFunction(clusterAccessor, appAccessor, "unknown", replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
@@ -124,7 +124,7 @@ func TestLegacyGetClusterFilterWithFixedShard(t *testing.T) {
clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
appAccessor, _, _, _, _, _ := createTestApps()
replicasCount := 5
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Maybe()
filter := GetDistributionFunction(clusterAccessor, appAccessor, common.DefaultShardingAlgorithm, replicasCount)
assert.Equal(t, 0, filter(nil))
assert.Equal(t, 4, filter(&cluster1))
@@ -151,7 +151,7 @@ func TestRoundRobinGetClusterFilterWithFixedShard(t *testing.T) {
clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters()
appAccessor, _, _, _, _, _ := createTestApps()
replicasCount := 4
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Maybe()
filter := GetDistributionFunction(clusterAccessor, appAccessor, common.RoundRobinShardingAlgorithm, replicasCount)
assert.Equal(t, 0, filter(nil))
@@ -182,7 +182,7 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) {
t.Run("replicas set to 1", func(t *testing.T) {
replicasCount := 1
db.On("GetApplicationControllerReplicas").Return(replicasCount).Once()
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Once()
distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
@@ -194,7 +194,7 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) {
t.Run("replicas set to 2", func(t *testing.T) {
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount).Once()
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Once()
distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
@@ -206,7 +206,7 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) {
t.Run("replicas set to 3", func(t *testing.T) {
replicasCount := 3
db.On("GetApplicationControllerReplicas").Return(replicasCount).Once()
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Once()
distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
@@ -232,7 +232,7 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterNumber
t.Setenv(common.EnvControllerReplicas, strconv.Itoa(replicasCount))
_, db, _, _, _, _, _ := createTestClusters()
clusterAccessor := func() []*v1alpha1.Cluster { return clusterPointers }
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Maybe()
distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount)
for i, c := range clusterPointers {
assert.Equal(t, i%2, distributionFunction(c))
@@ -240,7 +240,7 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterNumber
}
func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterIsAddedAndRemoved(t *testing.T) {
db := dbmocks.ArgoDB{}
db := &dbmocks.ArgoDB{}
cluster1 := createCluster("cluster1", "1")
cluster2 := createCluster("cluster2", "2")
cluster3 := createCluster("cluster3", "3")
@@ -252,10 +252,10 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterIsAdde
clusterAccessor := getClusterAccessor(clusters)
clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
db.EXPECT().ListClusters(mock.Anything).Return(clusterList, nil)
// Test with replicas set to 2
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount)
distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
assert.Equal(t, 0, distributionFunction(&cluster1))
@@ -277,7 +277,7 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterIsAdde
}
func TestConsistentHashingWhenClusterIsAddedAndRemoved(t *testing.T) {
db := dbmocks.ArgoDB{}
db := &dbmocks.ArgoDB{}
clusterCount := 133
prefix := "cluster"
@@ -290,10 +290,10 @@ func TestConsistentHashingWhenClusterIsAddedAndRemoved(t *testing.T) {
clusterAccessor := getClusterAccessor(clusters)
appAccessor, _, _, _, _, _ := createTestApps()
clusterList := &v1alpha1.ClusterList{Items: clusters}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
db.EXPECT().ListClusters(mock.Anything).Return(clusterList, nil)
// Test with replicas set to 3
replicasCount := 3
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount)
distributionFunction := ConsistentHashingWithBoundedLoadsDistributionFunction(clusterAccessor, appAccessor, replicasCount)
assert.Equal(t, 0, distributionFunction(nil))
distributionMap := map[int]int{}
@@ -347,32 +347,32 @@ func TestConsistentHashingWhenClusterIsAddedAndRemoved(t *testing.T) {
}
func TestConsistentHashingWhenClusterWithZeroReplicas(t *testing.T) {
db := dbmocks.ArgoDB{}
db := &dbmocks.ArgoDB{}
clusters := []v1alpha1.Cluster{createCluster("cluster-01", "01")}
clusterAccessor := getClusterAccessor(clusters)
clusterList := &v1alpha1.ClusterList{Items: clusters}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
db.EXPECT().ListClusters(mock.Anything).Return(clusterList, nil)
appAccessor, _, _, _, _, _ := createTestApps()
// Test with replicas set to 0
replicasCount := 0
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount)
distributionFunction := ConsistentHashingWithBoundedLoadsDistributionFunction(clusterAccessor, appAccessor, replicasCount)
assert.Equal(t, -1, distributionFunction(nil))
}
func TestConsistentHashingWhenClusterWithFixedShard(t *testing.T) {
db := dbmocks.ArgoDB{}
db := &dbmocks.ArgoDB{}
var fixedShard int64 = 1
cluster := &v1alpha1.Cluster{ID: "1", Shard: &fixedShard}
clusters := []v1alpha1.Cluster{*cluster}
clusterAccessor := getClusterAccessor(clusters)
clusterList := &v1alpha1.ClusterList{Items: clusters}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
db.EXPECT().ListClusters(mock.Anything).Return(clusterList, nil)
// Test with replicas set to 5
replicasCount := 5
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount)
appAccessor, _, _, _, _, _ := createTestApps()
distributionFunction := ConsistentHashingWithBoundedLoadsDistributionFunction(clusterAccessor, appAccessor, replicasCount)
assert.Equal(t, fixedShard, int64(distributionFunction(cluster)))
@@ -381,7 +381,7 @@ func TestConsistentHashingWhenClusterWithFixedShard(t *testing.T) {
func TestGetShardByIndexModuloReplicasCountDistributionFunction(t *testing.T) {
clusters, db, cluster1, cluster2, _, _, _ := createTestClusters()
replicasCount := 2
db.On("GetApplicationControllerReplicas").Return(replicasCount)
db.EXPECT().GetApplicationControllerReplicas().Return(replicasCount).Maybe()
distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount)
// Test that the function returns the correct shard for cluster1 and cluster2
@@ -419,7 +419,7 @@ func TestInferShard(t *testing.T) {
}
func createTestClusters() (clusterAccessor, *dbmocks.ArgoDB, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster) {
db := dbmocks.ArgoDB{}
db := &dbmocks.ArgoDB{}
cluster1 := createCluster("cluster1", "1")
cluster2 := createCluster("cluster2", "2")
cluster3 := createCluster("cluster3", "3")
@@ -428,10 +428,10 @@ func createTestClusters() (clusterAccessor, *dbmocks.ArgoDB, v1alpha1.Cluster, v
clusters := []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}
db.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{
db.EXPECT().ListClusters(mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{
cluster1, cluster2, cluster3, cluster4, cluster5,
}}, nil)
return getClusterAccessor(clusters), &db, cluster1, cluster2, cluster3, cluster4, cluster5
return getClusterAccessor(clusters), db, cluster1, cluster2, cluster3, cluster4, cluster5
}
func getClusterAccessor(clusters []v1alpha1.Cluster) clusterAccessor {

View File

@@ -16,14 +16,14 @@ import (
func TestLargeShuffle(t *testing.T) {
t.Skip()
db := dbmocks.ArgoDB{}
db := &dbmocks.ArgoDB{}
clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{}}
for i := 0; i < math.MaxInt/4096; i += 256 {
// fmt.Fprintf(os.Stdout, "%d", i)
cluster := createCluster(fmt.Sprintf("cluster-%d", i), strconv.Itoa(i))
clusterList.Items = append(clusterList.Items, cluster)
}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
db.EXPECT().ListClusters(mock.Anything).Return(clusterList, nil)
clusterAccessor := getClusterAccessor(clusterList.Items)
// Test with replicas set to 256
replicasCount := 256
@@ -36,7 +36,7 @@ func TestLargeShuffle(t *testing.T) {
func TestShuffle(t *testing.T) {
t.Skip()
db := dbmocks.ArgoDB{}
db := &dbmocks.ArgoDB{}
cluster1 := createCluster("cluster1", "10")
cluster2 := createCluster("cluster2", "20")
cluster3 := createCluster("cluster3", "30")
@@ -46,7 +46,7 @@ func TestShuffle(t *testing.T) {
cluster25 := createCluster("cluster6", "25")
clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5, cluster6}}
db.On("ListClusters", mock.Anything).Return(clusterList, nil)
db.EXPECT().ListClusters(mock.Anything).Return(clusterList, nil)
clusterAccessor := getClusterAccessor(clusterList.Items)
// Test with replicas set to 3
t.Setenv(common.EnvControllerReplicas, "3")

View File

@@ -41,13 +41,18 @@ import (
"github.com/argoproj/argo-cd/v3/util/argo/normalizers"
appstatecache "github.com/argoproj/argo-cd/v3/util/cache/appstate"
"github.com/argoproj/argo-cd/v3/util/db"
"github.com/argoproj/argo-cd/v3/util/env"
"github.com/argoproj/argo-cd/v3/util/gpg"
utilio "github.com/argoproj/argo-cd/v3/util/io"
"github.com/argoproj/argo-cd/v3/util/settings"
"github.com/argoproj/argo-cd/v3/util/stats"
)
var ErrCompareStateRepo = errors.New("failed to get repo objects")
var (
ErrCompareStateRepo = errors.New("failed to get repo objects")
processManifestGeneratePathsEnabled = env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_PROCESS_MANIFEST_GENERATE_PATHS", true)
)
type resourceInfoProviderStub struct{}
@@ -70,7 +75,7 @@ type managedResource struct {
// AppStateManager defines methods which allow to compare application spec and actual application state.
type AppStateManager interface {
CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localObjects []string, hasMultipleSources bool) (*comparisonResult, error)
CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache, noRevisionCache bool, localObjects []string, hasMultipleSources bool) (*comparisonResult, error)
SyncAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, state *v1alpha1.OperationState)
GetRepoObjs(ctx context.Context, app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject, sendRuntimeState bool) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, bool, error)
}
@@ -253,7 +258,14 @@ func (m *appStateManager) GetRepoObjs(ctx context.Context, app *v1alpha1.Applica
appNamespace = ""
}
if !source.IsHelm() && !source.IsOCI() && syncedRevision != "" && keyManifestGenerateAnnotationExists && keyManifestGenerateAnnotationVal != "" {
updateRevisions := processManifestGeneratePathsEnabled &&
// updating revisions result is not required if automated sync is not enabled
app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.Automated != nil &&
// using updating revisions gains performance only if manifest generation is required.
// just reading pre-generated manifests is comparable to updating revisions time-wise
app.Status.SourceType != v1alpha1.ApplicationSourceTypeDirectory
if updateRevisions && repo.Depth == 0 && !source.IsHelm() && !source.IsOCI() && syncedRevision != "" && syncedRevision != revision && keyManifestGenerateAnnotationExists && keyManifestGenerateAnnotationVal != "" {
// Validate the manifest-generate-path annotation to avoid generating manifests if it has not changed.
updateRevisionResult, err := repoClient.UpdateRevisionForPaths(ctx, &apiclient.UpdateRevisionForPathsRequest{
Repo: repo,
@@ -350,7 +362,7 @@ func (m *appStateManager) GetRepoObjs(ctx context.Context, app *v1alpha1.Applica
}
// ResolveGitRevision will resolve the given revision to a full commit SHA. Only works for git.
func (m *appStateManager) ResolveGitRevision(repoURL string, revision string) (string, error) {
func (m *appStateManager) ResolveGitRevision(repoURL, revision string) (string, error) {
conn, repoClient, err := m.repoClientset.NewRepoServerClient()
if err != nil {
return "", fmt.Errorf("failed to connect to repo server: %w", err)
@@ -529,7 +541,7 @@ func isManagedNamespace(ns *unstructured.Unstructured, app *v1alpha1.Application
// CompareAppState compares application git state to the live app state, using the specified
// revision and supplied source. If revision or overrides are empty, then compares against
// revision and overrides in the app spec.
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string, hasMultipleSources bool) (*comparisonResult, error) {
func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache, noRevisionCache bool, localManifests []string, hasMultipleSources bool) (*comparisonResult, error) {
ts := stats.NewTimingStats()
logCtx := log.WithFields(applog.GetAppLogFields(app))

View File

@@ -48,7 +48,7 @@ func TestCompareAppStateEmpty(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -66,7 +66,7 @@ func TestCompareAppStateEmpty(t *testing.T) {
// TestCompareAppStateRepoError tests the case when CompareAppState notices a repo error
func TestCompareAppStateRepoError(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{manifestResponses: make([]*apiclient.ManifestResponse, 3)}, errors.New("test repo error"))
ctrl := newFakeController(t.Context(), &fakeData{manifestResponses: make([]*apiclient.ManifestResponse, 3)}, errors.New("test repo error"))
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -112,7 +112,7 @@ func TestCompareAppStateNamespaceMetadataDiffers(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -161,7 +161,7 @@ func TestCompareAppStateNamespaceMetadataDiffersToManifest(t *testing.T) {
kube.GetResourceKey(ns): ns,
},
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -219,7 +219,7 @@ func TestCompareAppStateNamespaceMetadata(t *testing.T) {
kube.GetResourceKey(ns): ns,
},
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -278,7 +278,7 @@ func TestCompareAppStateNamespaceMetadataIsTheSame(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -306,7 +306,7 @@ func TestCompareAppStateMissing(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -338,7 +338,7 @@ func TestCompareAppStateExtra(t *testing.T) {
key: pod,
},
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -369,7 +369,7 @@ func TestCompareAppStateHook(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -401,7 +401,7 @@ func TestCompareAppStateSkipHook(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -431,7 +431,7 @@ func TestCompareAppStateCompareOptionIgnoreExtraneous(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
@@ -465,7 +465,7 @@ func TestCompareAppStateExtraHook(t *testing.T) {
key: pod,
},
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -494,7 +494,7 @@ func TestAppRevisionsSingleSource(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
app := newFakeApp()
revisions := make([]string, 0)
@@ -534,7 +534,7 @@ func TestAppRevisionsMultiSource(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
app := newFakeMultiSourceApp()
revisions := make([]string, 0)
@@ -583,7 +583,7 @@ func TestCompareAppStateDuplicatedNamespacedResources(t *testing.T) {
kube.GetResourceKey(obj3): obj3,
},
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -624,7 +624,7 @@ func TestCompareAppStateManagedNamespaceMetadataWithLiveNsDoesNotGetPruned(t *te
kube.GetResourceKey(ns): ns,
},
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, []string{}, app.Spec.Sources, false, false, nil, false)
require.NoError(t, err)
@@ -676,7 +676,7 @@ func TestCompareAppStateWithManifestGeneratePath(t *testing.T) {
updateRevisionForPathsResponse: &apiclient.UpdateRevisionForPathsResponse{},
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
revisions := make([]string, 0)
revisions = append(revisions, "abc123")
compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, false)
@@ -698,7 +698,7 @@ func TestSetHealth(t *testing.T) {
Namespace: "default",
},
})
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
@@ -734,7 +734,7 @@ func TestPreserveStatusTimestamp(t *testing.T) {
Namespace: "default",
},
})
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
@@ -770,7 +770,7 @@ func TestSetHealthSelfReferencedApp(t *testing.T) {
Namespace: "default",
},
})
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
@@ -799,7 +799,7 @@ func TestSetManagedResourcesWithOrphanedResources(t *testing.T) {
proj.Spec.OrphanedResources = &v1alpha1.OrphanedResourcesMonitorSettings{}
app := newFakeApp()
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, proj},
namespacedResources: map[kube.ResourceKey]namespacedResource{
kube.NewResourceKey("apps", kube.DeploymentKind, app.Namespace, "guestbook"): {
@@ -828,7 +828,7 @@ func TestSetManagedResourcesWithResourcesOfAnotherApp(t *testing.T) {
app2 := newFakeApp()
app2.Name = "app2"
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app1, app2, proj},
namespacedResources: map[kube.ResourceKey]namespacedResource{
kube.NewResourceKey("apps", kube.DeploymentKind, app2.Namespace, "guestbook"): {
@@ -852,7 +852,7 @@ func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, proj},
configMapData: map[string]string{
"resource.customizations": "invalid setting",
@@ -878,7 +878,7 @@ func TestSetManagedResourcesKnownOrphanedResourceExceptions(t *testing.T) {
app := newFakeApp()
app.Namespace = "default"
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, proj},
namespacedResources: map[kube.ResourceKey]namespacedResource{
kube.NewResourceKey("apps", kube.DeploymentKind, app.Namespace, "guestbook"): {
@@ -902,7 +902,7 @@ func TestSetManagedResourcesKnownOrphanedResourceExceptions(t *testing.T) {
func Test_appStateManager_persistRevisionHistory(t *testing.T) {
app := newFakeApp()
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app},
}, nil)
manager := ctrl.appStateManager.(*appStateManager)
@@ -1007,7 +1007,7 @@ func TestSignedResponseNoSignatureRequired(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1034,7 +1034,7 @@ func TestSignedResponseNoSignatureRequired(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1066,7 +1066,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1093,7 +1093,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1120,7 +1120,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1147,7 +1147,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1175,7 +1175,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
testProj := signedProj
testProj.Spec.SignatureKeys[0].KeyID = "4AEE18F83AFDEB24"
sources := make([]v1alpha1.ApplicationSource, 0)
@@ -1207,7 +1207,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
}
// it doesn't matter for our test whether local manifests are valid
localManifests := []string{"foobar"}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1237,7 +1237,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1267,7 +1267,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) {
}
// it doesn't matter for our test whether local manifests are valid
localManifests := []string{""}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1395,7 +1395,7 @@ func TestIsLiveResourceManaged(t *testing.T) {
},
},
})
ctrl := newFakeController(&fakeData{
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, &defaultProj},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
@@ -1765,7 +1765,7 @@ func TestCompareAppStateDefaultRevisionUpdated(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1788,7 +1788,7 @@ func TestCompareAppStateRevisionUpdatedWithHelmSource(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
sources := make([]v1alpha1.ApplicationSource, 0)
sources = append(sources, app.Spec.GetSource())
revisions := make([]string, 0)
@@ -1807,10 +1807,10 @@ func Test_normalizeClusterScopeTracking(t *testing.T) {
Namespace: "test",
},
})
c := cachemocks.ClusterCache{}
c.On("IsNamespaced", mock.Anything).Return(false, nil)
c := &cachemocks.ClusterCache{}
c.EXPECT().IsNamespaced(mock.Anything).Return(false, nil)
var called bool
err := normalizeClusterScopeTracking([]*unstructured.Unstructured{obj}, &c, func(u *unstructured.Unstructured) error {
err := normalizeClusterScopeTracking([]*unstructured.Unstructured{obj}, c, func(u *unstructured.Unstructured) error {
// We expect that the normalization function will call this callback with an obj that has had the namespace set
// to empty.
called = true
@@ -1838,7 +1838,7 @@ func TestCompareAppState_DoesNotCallUpdateRevisionForPaths_ForOCI(t *testing.T)
Revision: "abc123",
},
}
ctrl := newFakeControllerWithResync(&data, time.Minute, nil, errors.New("this should not be called"))
ctrl := newFakeControllerWithResync(t.Context(), &data, time.Minute, nil, errors.New("this should not be called"))
source := app.Spec.GetSource()
source.RepoURL = "oci://example.com/argo/argo-cd"

View File

@@ -75,7 +75,7 @@ func TestPersistRevisionHistory(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
// Sync with source unspecified
opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{
@@ -121,7 +121,7 @@ func TestPersistManagedNamespaceMetadataState(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
// Sync with source unspecified
opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{
@@ -152,7 +152,7 @@ func TestPersistRevisionHistoryRollback(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
// Sync with source specified
source := v1alpha1.ApplicationSource{
@@ -206,7 +206,7 @@ func TestSyncComparisonError(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
// Sync with source unspecified
opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{
@@ -263,7 +263,7 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
},
managedLiveObjs: liveObjects,
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
return &fixture{
application: app,
@@ -350,7 +350,7 @@ func TestSyncWindowDeniesSync(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
return &fixture{
application: app,
@@ -1620,7 +1620,7 @@ func TestSyncWithImpersonate(t *testing.T) {
},
additionalObjs: additionalObjs,
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
return &fixture{
application: app,
project: project,
@@ -1780,7 +1780,7 @@ func TestClientSideApplyMigration(t *testing.T) {
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
}
ctrl := newFakeController(&data, nil)
ctrl := newFakeController(t.Context(), &data, nil)
return &fixture{
application: app,

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

View File

@@ -129,33 +129,30 @@ It is also possible to add an optional flyout widget to your extension. It can b
Below is an example of an extension using the flyout widget:
```javascript
((window) => {
const component = (props: {
openFlyout: () => any
}) => {
const component = (props: { openFlyout: () => any }) => {
return React.createElement(
"div",
{
style: { padding: "10px" },
onClick: () => props.openFlyout()
},
"Hello World"
"div",
{
style: { padding: "10px" },
onClick: () => props.openFlyout(),
},
"Hello World"
);
};
const flyout = () => {
return React.createElement(
"div",
{ style: { padding: "10px" } },
"This is a flyout"
"div",
{ style: { padding: "10px" } },
"This is a flyout"
);
};
window.extensionsAPI.registerStatusPanelExtension(
component,
"My Extension",
"my_extension",
flyout
component,
"My Extension",
"my_extension",
flyout
);
})(window);
```
@@ -183,7 +180,9 @@ The callback function `shouldDisplay` should return true if the extension should
```typescript
const shouldDisplay = (app: Application) => {
return application.metadata?.labels?.['application.environmentLabelKey'] === "prd";
return (
application.metadata?.labels?.["application.environmentLabelKey"] === "prd"
);
};
```
@@ -196,28 +195,64 @@ Below is an example of a simple extension with a flyout widget:
};
const flyout = () => {
return React.createElement(
"div",
{ style: { padding: "10px" } },
"This is a flyout"
"div",
{ style: { padding: "10px" } },
"This is a flyout"
);
};
const component = () => {
return React.createElement(
"div",
{
onClick: () => flyout()
},
"Toolbar Extension Test"
"div",
{
onClick: () => flyout(),
},
"Toolbar Extension Test"
);
};
window.extensionsAPI.registerTopBarActionMenuExt(
component,
"Toolbar Extension Test",
"Toolbar_Extension_Test",
flyout,
shouldDisplay,
'',
true
component,
"Toolbar Extension Test",
"Toolbar_Extension_Test",
flyout,
shouldDisplay,
"",
true
);
})(window);
```
```
## App View Extensions
App View extensions allow you to create a new Application Details View for an application. This view would be selectable alongside the other views like the Node Tree, Pod, and Network views. When the extension's icon is clicked, the extension's component is rendered as the main content of the application view.
Register this extension through the `extensionsAPI.registerAppViewExtension` method.
```typescript
registerAppViewExtension(
component: ExtensionComponent, // the component to be rendered
title: string, // the title of the page once the component is rendered
icon: string, // the favicon classname for the icon tab
)
```
Below is an example of a simple extension:
```javascript
((window) => {
const component = () => {
return React.createElement(
"div",
{ style: { padding: "10px" } },
"Hello World"
);
};
window.extensionsAPI.registerAppViewExtension(
component,
"My Extension",
"fa-question-circle"
);
})(window);
```
Example rendered extension:
![destination](../../assets/application-view-extension.png)

View File

@@ -1223,7 +1223,7 @@ The `resource.exclusions` node is a list of objects. Each object can have:
* `apiGroups` A list of globs to match the API group.
* `kinds` A list of kinds to match. Can be `"*"` to match all.
* `clusters` A list of globs to match the cluster.
* `clusters` A list of globs to match the cluster URL.
If all three match, then the resource is ignored.

View File

@@ -533,3 +533,28 @@ Once the endpoint is enabled, you can use go profile tool to collect the CPU and
$ kubectl port-forward svc/argocd-metrics 8082:8082
$ go tool pprof http://localhost:8082/debug/pprof/heap
```
## Shallow Clone
Monorepos can be large and slow to clone. To speed up the clone process, you can use the `depth: "1"` repository option:
```yaml
apiVersion: v1
stringData:
depth: "1"
type: "git"
url: "https://github.com/argoproj/argocd-example-apps.git"
kind: Secret
metadata:
annotations:
managed-by: argocd.argoproj.io
labels:
argocd.argoproj.io/secret-type: repository
name: my-repo
namespace: argocd
type: Opaque
```
> [!NOTE] You can use the `argocd repo add <repo-url> --depth` command to add a repository with shallow cloning enabled.
When shallow cloning, the repository is cloned with a depth of 1, which means only the required commit is cloned as opposed to the full history. This approach makes sense when the repository has a large history.

View File

@@ -12,6 +12,19 @@ The Email notification service sends email notifications using SMTP protocol and
* `html` - optional bool, true or false
* `insecure_skip_verify` - optional bool, true or false
### Using Gmail
When configuring Gmail as the SMTP service:
* `username` - Must be your Gmail address.
* `password` - Use an App Password, not your regular Gmail password.
To Generate an app password, follow this link https://myaccount.google.com/apppasswords
!!! note
This applies to personal Gmail accounts (non-Google Workspace). For Google Workspace users, SMTP settings
and authentication methods may differ.
## Example
The following snippet contains sample Gmail service configuration:
@@ -23,11 +36,11 @@ metadata:
name: argocd-notifications-cm
data:
service.email.gmail: |
username: $email-username
password: $email-password
username: $username
password: $password
host: smtp.gmail.com
port: 465
from: $email-username
from: $email-address
```
Without authentication:
@@ -41,7 +54,7 @@ data:
service.email.example: |
host: smtp.example.com
port: 587
from: $email-username
from: $email-address
```
## Template

View File

@@ -6,5 +6,5 @@ mkdocs-material==7.1.8
markdown_include==0.8.1
pygments==2.19.2
jinja2==3.1.6
markdown==3.9
markdown==3.10
pymdown-extensions==10.16.1

View File

@@ -13,8 +13,8 @@ recent minor releases.
| | Critical | High | Medium | Low |
|---:|:--------:|:----:|:------:|:---:|
| [go.mod](master/argocd-test.html) | 0 | 1 | 5 | 0 |
| [ui/yarn.lock](master/argocd-test.html) | 0 | 0 | 1 | 2 |
| [go.mod](master/argocd-test.html) | 0 | 0 | 5 | 0 |
| [ui/yarn.lock](master/argocd-test.html) | 0 | 0 | 2 | 2 |
| [dex:v2.43.0](master/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 0 | 0 | 3 |
| [haproxy:3.0.8-alpine](master/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 0 | 0 | 3 |
| [redis:8.2.1-alpine](master/public.ecr.aws_docker_library_redis_8.2.1-alpine.html) | 0 | 0 | 0 | 3 |
@@ -22,25 +22,25 @@ recent minor releases.
| [install.yaml](master/argocd-iac-install.html) | - | - | - | - |
| [namespace-install.yaml](master/argocd-iac-namespace-install.html) | - | - | - | - |
### v3.2.0-rc3
### v3.2.0-rc4
| | Critical | High | Medium | Low |
|---:|:--------:|:----:|:------:|:---:|
| [go.mod](v3.2.0-rc3/argocd-test.html) | 0 | 1 | 5 | 0 |
| [ui/yarn.lock](v3.2.0-rc3/argocd-test.html) | 0 | 0 | 1 | 2 |
| [dex:v2.43.0](v3.2.0-rc3/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 0 | 0 | 3 |
| [haproxy:3.0.8-alpine](v3.2.0-rc3/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 0 | 0 | 3 |
| [redis:8.2.1-alpine](v3.2.0-rc3/public.ecr.aws_docker_library_redis_8.2.1-alpine.html) | 0 | 0 | 0 | 3 |
| [argocd:v3.2.0-rc3](v3.2.0-rc3/quay.io_argoproj_argocd_v3.2.0-rc3.html) | 0 | 0 | 3 | 9 |
| [install.yaml](v3.2.0-rc3/argocd-iac-install.html) | - | - | - | - |
| [namespace-install.yaml](v3.2.0-rc3/argocd-iac-namespace-install.html) | - | - | - | - |
| [go.mod](v3.2.0-rc4/argocd-test.html) | 0 | 1 | 5 | 0 |
| [ui/yarn.lock](v3.2.0-rc4/argocd-test.html) | 0 | 0 | 2 | 2 |
| [dex:v2.43.0](v3.2.0-rc4/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 0 | 0 | 3 |
| [haproxy:3.0.8-alpine](v3.2.0-rc4/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 0 | 0 | 3 |
| [redis:8.2.2-alpine](v3.2.0-rc4/public.ecr.aws_docker_library_redis_8.2.2-alpine.html) | 0 | 0 | 0 | 0 |
| [argocd:v3.2.0-rc4](v3.2.0-rc4/quay.io_argoproj_argocd_v3.2.0-rc4.html) | 0 | 0 | 3 | 9 |
| [install.yaml](v3.2.0-rc4/argocd-iac-install.html) | - | - | - | - |
| [namespace-install.yaml](v3.2.0-rc4/argocd-iac-namespace-install.html) | - | - | - | - |
### v3.1.9
| | Critical | High | Medium | Low |
|---:|:--------:|:----:|:------:|:---:|
| [go.mod](v3.1.9/argocd-test.html) | 0 | 1 | 5 | 0 |
| [ui/yarn.lock](v3.1.9/argocd-test.html) | 1 | 0 | 1 | 2 |
| [ui/yarn.lock](v3.1.9/argocd-test.html) | 1 | 0 | 2 | 2 |
| [dex:v2.43.0](v3.1.9/ghcr.io_dexidp_dex_v2.43.0.html) | 0 | 0 | 0 | 3 |
| [haproxy:3.0.8-alpine](v3.1.9/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 0 | 0 | 3 |
| [redis:7.2.11-alpine](v3.1.9/public.ecr.aws_docker_library_redis_7.2.11-alpine.html) | 0 | 0 | 0 | 0 |
@@ -53,7 +53,7 @@ recent minor releases.
| | Critical | High | Medium | Low |
|---:|:--------:|:----:|:------:|:---:|
| [go.mod](v3.0.20/argocd-test.html) | 0 | 4 | 5 | 0 |
| [ui/yarn.lock](v3.0.20/argocd-test.html) | 1 | 1 | 2 | 4 |
| [ui/yarn.lock](v3.0.20/argocd-test.html) | 1 | 1 | 3 | 4 |
| [dex:v2.41.1](v3.0.20/ghcr.io_dexidp_dex_v2.41.1.html) | 0 | 1 | 0 | 7 |
| [haproxy:3.0.8-alpine](v3.0.20/public.ecr.aws_docker_library_haproxy_3.0.8-alpine.html) | 0 | 0 | 0 | 3 |
| [redis:7.2.11-alpine](v3.0.20/public.ecr.aws_docker_library_redis_7.2.11-alpine.html) | 0 | 0 | 0 | 0 |
@@ -67,7 +67,7 @@ recent minor releases.
| | Critical | High | Medium | Low |
|---:|:--------:|:----:|:------:|:---:|
| [go.mod](v2.14.20/argocd-test.html) | 0 | 2 | 8 | 0 |
| [ui/yarn.lock](v2.14.20/argocd-test.html) | 1 | 0 | 2 | 3 |
| [ui/yarn.lock](v2.14.20/argocd-test.html) | 1 | 0 | 3 | 3 |
| [dex:v2.41.1](v2.14.20/ghcr.io_dexidp_dex_v2.41.1.html) | 0 | 1 | 0 | 7 |
| [haproxy:2.6.17-alpine](v2.14.20/public.ecr.aws_docker_library_haproxy_2.6.17-alpine.html) | 0 | 1 | 2 | 9 |
| [redis:7.0.15-alpine](v2.14.20/public.ecr.aws_docker_library_redis_7.0.15-alpine.html) | 0 | 0 | 0 | 7 |

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:24:48 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:24:10 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: 25607
Line number: 25616
</li>
</ul>
@@ -933,7 +933,7 @@
</li>
<li class="card__meta__item">
Line number: 25944
Line number: 25953
</li>
</ul>
@@ -1049,7 +1049,7 @@
</li>
<li class="card__meta__item">
Line number: 25403
Line number: 25412
</li>
</ul>
@@ -1107,7 +1107,7 @@
</li>
<li class="card__meta__item">
Line number: 25351
Line number: 25360
</li>
</ul>
@@ -1165,7 +1165,7 @@
</li>
<li class="card__meta__item">
Line number: 25465
Line number: 25474
</li>
</ul>
@@ -1223,7 +1223,7 @@
</li>
<li class="card__meta__item">
Line number: 25578
Line number: 25587
</li>
</ul>
@@ -1281,7 +1281,7 @@
</li>
<li class="card__meta__item">
Line number: 25602
Line number: 25611
</li>
</ul>
@@ -1339,7 +1339,7 @@
</li>
<li class="card__meta__item">
Line number: 25944
Line number: 25953
</li>
</ul>
@@ -1397,7 +1397,7 @@
</li>
<li class="card__meta__item">
Line number: 25661
Line number: 25670
</li>
</ul>
@@ -1455,7 +1455,7 @@
</li>
<li class="card__meta__item">
Line number: 26032
Line number: 26041
</li>
</ul>
@@ -1513,7 +1513,7 @@
</li>
<li class="card__meta__item">
Line number: 26442
Line number: 26451
</li>
</ul>
@@ -1565,7 +1565,7 @@
</li>
<li class="card__meta__item">
Line number: 25383
Line number: 25392
</li>
</ul>
@@ -1669,7 +1669,7 @@
</li>
<li class="card__meta__item">
Line number: 25351
Line number: 25360
</li>
</ul>
@@ -1721,7 +1721,7 @@
</li>
<li class="card__meta__item">
Line number: 25578
Line number: 25587
</li>
</ul>
@@ -1837,7 +1837,7 @@
</li>
<li class="card__meta__item">
Line number: 25351
Line number: 25360
</li>
</ul>
@@ -1895,7 +1895,7 @@
</li>
<li class="card__meta__item">
Line number: 25403
Line number: 25412
</li>
</ul>
@@ -1953,7 +1953,7 @@
</li>
<li class="card__meta__item">
Line number: 25465
Line number: 25474
</li>
</ul>
@@ -2011,7 +2011,7 @@
</li>
<li class="card__meta__item">
Line number: 25578
Line number: 25587
</li>
</ul>
@@ -2069,7 +2069,7 @@
</li>
<li class="card__meta__item">
Line number: 25602
Line number: 25611
</li>
</ul>
@@ -2127,7 +2127,7 @@
</li>
<li class="card__meta__item">
Line number: 25944
Line number: 25953
</li>
</ul>
@@ -2185,7 +2185,7 @@
</li>
<li class="card__meta__item">
Line number: 25661
Line number: 25670
</li>
</ul>
@@ -2243,7 +2243,7 @@
</li>
<li class="card__meta__item">
Line number: 26032
Line number: 26041
</li>
</ul>
@@ -2301,7 +2301,7 @@
</li>
<li class="card__meta__item">
Line number: 26442
Line number: 26451
</li>
</ul>
@@ -2413,7 +2413,7 @@
</li>
<li class="card__meta__item">
Line number: 25411
Line number: 25420
</li>
</ul>
@@ -2469,7 +2469,7 @@
</li>
<li class="card__meta__item">
Line number: 25386
Line number: 25395
</li>
</ul>
@@ -2525,7 +2525,7 @@
</li>
<li class="card__meta__item">
Line number: 25510
Line number: 25519
</li>
</ul>
@@ -2581,7 +2581,7 @@
</li>
<li class="card__meta__item">
Line number: 25595
Line number: 25604
</li>
</ul>
@@ -2637,7 +2637,7 @@
</li>
<li class="card__meta__item">
Line number: 25609
Line number: 25618
</li>
</ul>
@@ -2693,7 +2693,7 @@
</li>
<li class="card__meta__item">
Line number: 25952
Line number: 25961
</li>
</ul>
@@ -2749,7 +2749,7 @@
</li>
<li class="card__meta__item">
Line number: 25917
Line number: 25926
</li>
</ul>
@@ -2805,7 +2805,7 @@
</li>
<li class="card__meta__item">
Line number: 26341
Line number: 26350
</li>
</ul>
@@ -2861,7 +2861,7 @@
</li>
<li class="card__meta__item">
Line number: 26717
Line number: 26726
</li>
</ul>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:24:58 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:24:21 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: 1288
Line number: 1297
</li>
</ul>
@@ -887,7 +887,7 @@
</li>
<li class="card__meta__item">
Line number: 1625
Line number: 1634
</li>
</ul>
@@ -1003,7 +1003,7 @@
</li>
<li class="card__meta__item">
Line number: 1084
Line number: 1093
</li>
</ul>
@@ -1061,7 +1061,7 @@
</li>
<li class="card__meta__item">
Line number: 1032
Line number: 1041
</li>
</ul>
@@ -1119,7 +1119,7 @@
</li>
<li class="card__meta__item">
Line number: 1146
Line number: 1155
</li>
</ul>
@@ -1177,7 +1177,7 @@
</li>
<li class="card__meta__item">
Line number: 1259
Line number: 1268
</li>
</ul>
@@ -1235,7 +1235,7 @@
</li>
<li class="card__meta__item">
Line number: 1283
Line number: 1292
</li>
</ul>
@@ -1293,7 +1293,7 @@
</li>
<li class="card__meta__item">
Line number: 1625
Line number: 1634
</li>
</ul>
@@ -1351,7 +1351,7 @@
</li>
<li class="card__meta__item">
Line number: 1342
Line number: 1351
</li>
</ul>
@@ -1409,7 +1409,7 @@
</li>
<li class="card__meta__item">
Line number: 1713
Line number: 1722
</li>
</ul>
@@ -1467,7 +1467,7 @@
</li>
<li class="card__meta__item">
Line number: 2123
Line number: 2132
</li>
</ul>
@@ -1519,7 +1519,7 @@
</li>
<li class="card__meta__item">
Line number: 1064
Line number: 1073
</li>
</ul>
@@ -1623,7 +1623,7 @@
</li>
<li class="card__meta__item">
Line number: 1032
Line number: 1041
</li>
</ul>
@@ -1675,7 +1675,7 @@
</li>
<li class="card__meta__item">
Line number: 1259
Line number: 1268
</li>
</ul>
@@ -1791,7 +1791,7 @@
</li>
<li class="card__meta__item">
Line number: 1032
Line number: 1041
</li>
</ul>
@@ -1849,7 +1849,7 @@
</li>
<li class="card__meta__item">
Line number: 1084
Line number: 1093
</li>
</ul>
@@ -1907,7 +1907,7 @@
</li>
<li class="card__meta__item">
Line number: 1146
Line number: 1155
</li>
</ul>
@@ -1965,7 +1965,7 @@
</li>
<li class="card__meta__item">
Line number: 1259
Line number: 1268
</li>
</ul>
@@ -2023,7 +2023,7 @@
</li>
<li class="card__meta__item">
Line number: 1283
Line number: 1292
</li>
</ul>
@@ -2081,7 +2081,7 @@
</li>
<li class="card__meta__item">
Line number: 1625
Line number: 1634
</li>
</ul>
@@ -2139,7 +2139,7 @@
</li>
<li class="card__meta__item">
Line number: 1342
Line number: 1351
</li>
</ul>
@@ -2197,7 +2197,7 @@
</li>
<li class="card__meta__item">
Line number: 1713
Line number: 1722
</li>
</ul>
@@ -2255,7 +2255,7 @@
</li>
<li class="card__meta__item">
Line number: 2123
Line number: 2132
</li>
</ul>
@@ -2367,7 +2367,7 @@
</li>
<li class="card__meta__item">
Line number: 1092
Line number: 1101
</li>
</ul>
@@ -2423,7 +2423,7 @@
</li>
<li class="card__meta__item">
Line number: 1067
Line number: 1076
</li>
</ul>
@@ -2479,7 +2479,7 @@
</li>
<li class="card__meta__item">
Line number: 1191
Line number: 1200
</li>
</ul>
@@ -2535,7 +2535,7 @@
</li>
<li class="card__meta__item">
Line number: 1276
Line number: 1285
</li>
</ul>
@@ -2591,7 +2591,7 @@
</li>
<li class="card__meta__item">
Line number: 1290
Line number: 1299
</li>
</ul>
@@ -2647,7 +2647,7 @@
</li>
<li class="card__meta__item">
Line number: 1633
Line number: 1642
</li>
</ul>
@@ -2703,7 +2703,7 @@
</li>
<li class="card__meta__item">
Line number: 1598
Line number: 1607
</li>
</ul>
@@ -2759,7 +2759,7 @@
</li>
<li class="card__meta__item">
Line number: 2022
Line number: 2031
</li>
</ul>
@@ -2815,7 +2815,7 @@
</li>
<li class="card__meta__item">
Line number: 2398
Line number: 2407
</li>
</ul>

View File

@@ -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="9 known vulnerabilities found in 32 vulnerable dependency paths.">
<meta name="description" content="9 known vulnerabilities found in 29 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">
@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:22:42 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:22:06 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -501,7 +501,7 @@
<div class="meta-counts">
<div class="meta-count"><span>9</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>32 vulnerable dependency paths</span></div>
<div class="meta-count"><span>29 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2854</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -510,13 +510,13 @@
<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--high" data-snyk-test="high">
<h2 class="card__title">Improper Handling of Unexpected Data Type</h2>
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
<h2 class="card__title">Prototype Pollution</h2>
<div class="card__section">
<div class="card__labels">
<div class="label label--high">
<span class="label__text">high severity</span>
<div class="label label--medium">
<span class="label__text">medium severity</span>
</div>
</div>
@@ -524,21 +524,21 @@
<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
Manifest file: /argo-cd <span class="list-paths__item__arrow"></span> ui/yarn.lock
</li>
<li class="card__meta__item">
Package Manager: golang
Package Manager: npm
</li>
<li class="card__meta__item">
Vulnerable module:
golang.org/x/crypto/ssh/agent
min-document
</li>
<li class="card__meta__item">Introduced through:
github.com/argoproj/argo-cd/v3@0.0.0, code.gitea.io/sdk/gitea@0.22.0 and others
argo-cd-ui@1.0.0, react-hot-loader@3.1.3 and others
</li>
</ul>
@@ -550,56 +550,13 @@
<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
argo-cd-ui@1.0.0
<span class="list-paths__item__arrow"></span>
code.gitea.io/sdk/gitea@0.22.0
react-hot-loader@3.1.3
<span class="list-paths__item__arrow"></span>
golang.org/x/crypto/ssh/agent@0.43.0
</span>
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
github.com/argoproj/argo-cd/v3@0.0.0
global@4.4.0
<span class="list-paths__item__arrow"></span>
github.com/go-git/go-git/v5/plumbing/transport/ssh@5.14.0
<span class="list-paths__item__arrow"></span>
github.com/xanzy/ssh-agent@0.3.3
<span class="list-paths__item__arrow"></span>
golang.org/x/crypto/ssh/agent@0.43.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>
github.com/go-git/go-git/v5/plumbing/transport/client@5.14.0
<span class="list-paths__item__arrow"></span>
github.com/go-git/go-git/v5/plumbing/transport/ssh@5.14.0
<span class="list-paths__item__arrow"></span>
github.com/xanzy/ssh-agent@0.3.3
<span class="list-paths__item__arrow"></span>
golang.org/x/crypto/ssh/agent@0.43.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>
github.com/go-git/go-git/v5@5.14.0
<span class="list-paths__item__arrow"></span>
github.com/go-git/go-git/v5/plumbing/transport/client@5.14.0
<span class="list-paths__item__arrow"></span>
github.com/go-git/go-git/v5/plumbing/transport/ssh@5.14.0
<span class="list-paths__item__arrow"></span>
github.com/xanzy/ssh-agent@0.3.3
<span class="list-paths__item__arrow"></span>
golang.org/x/crypto/ssh/agent@0.43.0
min-document@2.19.0
</span>
@@ -611,31 +568,105 @@
<hr/>
<!-- Overview -->
<h2 id="overview">Overview</h2>
<p>Affected versions of this package are vulnerable to Improper Handling of Unexpected Data Type when functions including <code>List()</code> and <code>SignWithFlags()</code> process <code>*successAgentMsg</code>. This can be triggered by a malicious agent sending a single <code>0x06</code> byte (<code>SSH_AGENT_SUCCESS</code>), which is unmarshalled into a <code>*successAgentMsg</code>, causing a panic and client crash.</p>
<p>Affected versions of this package are vulnerable to Prototype Pollution via the <code>removeAttributeNS</code> function. An attacker can manipulate the prototype chain of JavaScript objects, potentially causing a denial-of-service attack by supplying malicious input that targets the <code>__proto__</code> property during namespace attribute removal.</p>
<p><strong>Notes</strong>:</p>
<p>This vulnerability is only exploitable if user input is passed without sanitization to the affected functions. The PoC has been validated as a theoretical vector, and a fixed version has been released.</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>
<p>Prototype Pollution is a vulnerability affecting JavaScript. Prototype Pollution refers to the ability to inject properties into existing JavaScript language construct prototypes, such as objects. JavaScript allows all Object attributes to be altered, including their magical attributes such as <code>__proto__</code>, <code>constructor</code> and <code>prototype</code>. An attacker manipulates these attributes to overwrite, or pollute, a JavaScript application object prototype of the base object by injecting other values. Properties on the <code>Object.prototype</code> are then inherited by all the JavaScript objects through the prototype chain. When that happens, this leads to either denial of service by triggering JavaScript exceptions, or it tampers with the application source code to force the code path that the attacker injects, thereby leading to remote code execution.</p>
<p>There are two main ways in which the pollution of prototypes occurs:</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><p>Unsafe <code>Object</code> recursive merge</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><p>Property definition by path</p>
</li>
</ul>
<h3 id="unsafe-object-recursive-merge">Unsafe Object recursive merge</h3>
<p>The logic of a vulnerable recursive merge function follows the following high-level model:</p>
<pre><code>merge (target, source)
foreach property of source
if property exists and is an object on both the target and the source
merge(target[property], source[property])
else
target[property] = source[property]
</code></pre>
<br>
<p>When the source object contains a property named <code>__proto__</code> defined with <code>Object.defineProperty()</code> , the condition that checks if the property exists and is an object on both the target and the source passes and the merge recurses with the target, being the prototype of <code>Object</code> and the source of <code>Object</code> as defined by the attacker. Properties are then copied on the <code>Object</code> prototype.</p>
<p>Clone operations are a special sub-class of unsafe recursive merges, which occur when a recursive merge is conducted on an empty object: <code>merge({},source)</code>.</p>
<p><code>lodash</code> and <code>Hoek</code> are examples of libraries susceptible to recursive merge attacks.</p>
<h3 id="property-definition-by-path">Property definition by path</h3>
<p>There are a few JavaScript libraries that use an API to define property values on an object based on a given path. The function that is generally affected contains this signature: <code>theFunction(object, path, value)</code></p>
<p>If the attacker can control the value of “path”, they can set this value to <code>__proto__.myValue</code>. <code>myValue</code> is then assigned to the prototype of the class of the object.</p>
<h2 id="types-of-attacks">Types of attacks</h2>
<p>There are a few methods by which Prototype Pollution can be manipulated:</p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Origin</th>
<th>Short description</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Denial of service (DoS)</strong></td>
<td>Client</td>
<td>This is the most likely attack. <br>DoS occurs when <code>Object</code> holds generic functions that are implicitly called for various operations (for example, <code>toString</code> and <code>valueOf</code>). <br> The attacker pollutes <code>Object.prototype.someattr</code> and alters its state to an unexpected value such as <code>Int</code> or <code>Object</code>. In this case, the code fails and is likely to cause a denial of service. <br><strong>For example:</strong> if an attacker pollutes <code>Object.prototype.toString</code> by defining it as an integer, if the codebase at any point was reliant on <code>someobject.toString()</code> it would fail.</td>
</tr>
<tr>
<td><strong>Remote Code Execution</strong></td>
<td>Client</td>
<td>Remote code execution is generally only possible in cases where the codebase evaluates a specific attribute of an object, and then executes that evaluation.<br><strong>For example:</strong> <code>eval(someobject.someattr)</code>. In this case, if the attacker pollutes <code>Object.prototype.someattr</code> they are likely to be able to leverage this in order to execute code.</td>
</tr>
<tr>
<td><strong>Property Injection</strong></td>
<td>Client</td>
<td>The attacker pollutes properties that the codebase relies on for their informative value, including security properties such as cookies or tokens.<br> <strong>For example:</strong> if a codebase checks privileges for <code>someuser.isAdmin</code>, then when the attacker pollutes <code>Object.prototype.isAdmin</code> and sets it to equal <code>true</code>, they can then achieve admin privileges.</td>
</tr>
</tbody></table>
<h2 id="affected-environments">Affected environments</h2>
<p>The following environments are susceptible to a Prototype Pollution attack:</p>
<ul>
<li><p>Application server</p>
</li>
<li><p>Web server</p>
</li>
<li><p>Web browser</p>
</li>
</ul>
<h2 id="how-to-prevent">How to prevent</h2>
<ol>
<li><p>Freeze the prototype— use <code>Object.freeze (Object.prototype)</code>.</p>
</li>
<li><p>Require schema validation of JSON input.</p>
</li>
<li><p>Avoid using unsafe recursive merge functions.</p>
</li>
<li><p>Consider using objects without prototypes (for example, <code>Object.create(null)</code>), breaking the prototype chain and preventing pollution.</p>
</li>
<li><p>As a best practice use <code>Map</code> instead of <code>Object</code>.</p>
</li>
</ol>
<h3 id="for-more-information-on-this-vulnerability-type">For more information on this vulnerability type:</h3>
<p><a href="https://github.com/HoLyVieR/prototype-pollution-nsec18/blob/master/paper/JavaScript_prototype_pollution_attack_in_NodeJS.pdf">Arteau, Oliver. “JavaScript prototype pollution attack in NodeJS application.” GitHub, 26 May 2018</a></p>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>There is no fixed version for <code>min-document</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>
<li><a href="https://github.com/golang/go/issues/75178">GitHub Issue</a></li>
<li><a href="https://github.com/Raynos/min-document/pull/55/commits/0d4e8192ef723fb869645256102a56ed922efd68">Github Commit</a></li>
<li><a href="https://github.com/Raynos/min-document/issues/54">GitHub Issue</a></li>
<li><a href="https://github.com/OrangeShieldInfos/PoCs/tree/main/JavaScript/prototype-pollution/CVE-2025-57352">POC</a></li>
<li><a href="https://github.com/Raynos/min-document/blob/bf7b69130a364b5c6fcb8e623bffe43054994c65/dom-element.js#L129">Vulnerable Code</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXCRYPTOSSHAGENT-12668891">More about this vulnerability</a></p>
<p><a href="https://snyk.io/vuln/SNYK-JS-MINDOCUMENT-13045385">More about this vulnerability</a></p>
</div>
</div><!-- .card -->
@@ -816,7 +847,7 @@
<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/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/hashicorp/go-retryablehttp@0.7.8
@@ -827,7 +858,7 @@
<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>
gitlab.com/gitlab-org/api/client-go@0.148.1
gitlab.com/gitlab-org/api/client-go@0.157.1
<span class="list-paths__item__arrow"></span>
github.com/hashicorp/go-retryablehttp@0.7.8
@@ -838,9 +869,9 @@
<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/argoproj/notifications-engine/pkg/subscriptions@#da04400446ff
github.com/argoproj/notifications-engine/pkg/subscriptions@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/hashicorp/go-retryablehttp@0.7.8
@@ -851,9 +882,9 @@
<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/argoproj/notifications-engine/pkg/cmd@#da04400446ff
github.com/argoproj/notifications-engine/pkg/cmd@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/hashicorp/go-retryablehttp@0.7.8
@@ -864,7 +895,7 @@
<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/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>
@@ -877,11 +908,11 @@
<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/argoproj/notifications-engine/pkg/api@#da04400446ff
github.com/argoproj/notifications-engine/pkg/api@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/subscriptions@#da04400446ff
github.com/argoproj/notifications-engine/pkg/subscriptions@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/hashicorp/go-retryablehttp@0.7.8
@@ -892,11 +923,11 @@
<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/argoproj/notifications-engine/pkg/controller@#da04400446ff
github.com/argoproj/notifications-engine/pkg/controller@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/subscriptions@#da04400446ff
github.com/argoproj/notifications-engine/pkg/subscriptions@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/hashicorp/go-retryablehttp@0.7.8
@@ -907,9 +938,9 @@
<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/argoproj/notifications-engine/pkg/subscriptions@#da04400446ff
github.com/argoproj/notifications-engine/pkg/subscriptions@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>
@@ -922,9 +953,9 @@
<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/argoproj/notifications-engine/pkg/cmd@#da04400446ff
github.com/argoproj/notifications-engine/pkg/cmd@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>
@@ -937,11 +968,11 @@
<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/argoproj/notifications-engine/pkg/api@#da04400446ff
github.com/argoproj/notifications-engine/pkg/api@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/subscriptions@#da04400446ff
github.com/argoproj/notifications-engine/pkg/subscriptions@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>
@@ -954,11 +985,11 @@
<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/argoproj/notifications-engine/pkg/controller@#da04400446ff
github.com/argoproj/notifications-engine/pkg/controller@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/subscriptions@#da04400446ff
github.com/argoproj/notifications-engine/pkg/subscriptions@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>
@@ -1035,7 +1066,7 @@
<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>
gitlab.com/gitlab-org/api/client-go@0.148.1
gitlab.com/gitlab-org/api/client-go@0.157.1
<span class="list-paths__item__arrow"></span>
github.com/hashicorp/go-cleanhttp@0.5.2
@@ -1046,7 +1077,7 @@
<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>
gitlab.com/gitlab-org/api/client-go@0.148.1
gitlab.com/gitlab-org/api/client-go@0.157.1
<span class="list-paths__item__arrow"></span>
github.com/hashicorp/go-retryablehttp@0.7.8
<span class="list-paths__item__arrow"></span>
@@ -1059,7 +1090,7 @@
<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/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>
@@ -1074,9 +1105,9 @@
<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/argoproj/notifications-engine/pkg/subscriptions@#da04400446ff
github.com/argoproj/notifications-engine/pkg/subscriptions@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>
@@ -1091,9 +1122,9 @@
<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/argoproj/notifications-engine/pkg/cmd@#da04400446ff
github.com/argoproj/notifications-engine/pkg/cmd@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>
@@ -1108,11 +1139,11 @@
<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/argoproj/notifications-engine/pkg/api@#da04400446ff
github.com/argoproj/notifications-engine/pkg/api@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/subscriptions@#da04400446ff
github.com/argoproj/notifications-engine/pkg/subscriptions@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>
@@ -1127,11 +1158,11 @@
<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/argoproj/notifications-engine/pkg/controller@#da04400446ff
github.com/argoproj/notifications-engine/pkg/controller@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/subscriptions@#da04400446ff
github.com/argoproj/notifications-engine/pkg/subscriptions@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/argoproj/notifications-engine/pkg/services@#da04400446ff
github.com/argoproj/notifications-engine/pkg/services@#58cdc54685b4
<span class="list-paths__item__arrow"></span>
github.com/opsgenie/opsgenie-go-sdk-v2/client@1.2.23
<span class="list-paths__item__arrow"></span>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:22:54 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:22:16 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -724,7 +724,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:23:01 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:22:22 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:23:10 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:22:29 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -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 55 vulnerable dependency paths.">
<meta name="description" content="18 known vulnerabilities found in 54 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">
@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:23:30 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:22:51 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -501,8 +501,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>19</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>55 vulnerable dependency paths</span></div>
<div class="meta-count"><span>18</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>54 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2312</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -511,88 +511,6 @@
<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--high" data-snyk-test="high">
<h2 class="card__title">Improper Handling of Unexpected Data Type</h2>
<div class="card__section">
<div class="card__labels">
<div class="label label--high">
<span class="label__text">high severity</span>
</div>
</div>
<hr/>
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:latest/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:
golang.org/x/crypto/ssh/agent
</li>
<li class="card__meta__item">Introduced through:
github.com/argoproj/argo-cd/v3@* and golang.org/x/crypto/ssh/agent@v0.43.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@*
<span class="list-paths__item__arrow"></span>
golang.org/x/crypto/ssh/agent@v0.43.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 Improper Handling of Unexpected Data Type when functions including <code>List()</code> and <code>SignWithFlags()</code> process <code>*successAgentMsg</code>. This can be triggered by a malicious agent sending a single <code>0x06</code> byte (<code>SSH_AGENT_SUCCESS</code>), which is unmarshalled into a <code>*successAgentMsg</code>, causing a panic and client crash.</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>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>
<li><a href="https://github.com/golang/go/issues/75178">GitHub Issue</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXCRYPTOSSHAGENT-12668891">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">Directory Traversal</h2>
<div class="card__section">

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:34:43 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:34:18 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:34:53 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:34:28 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -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="16 known vulnerabilities found in 64 vulnerable dependency paths.">
<meta name="description" content="17 known vulnerabilities found in 65 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">
@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:32:41 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:32:11 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -499,8 +499,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>16</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>64 vulnerable dependency paths</span></div>
<div class="meta-count"><span>17</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>65 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2092</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -1031,7 +1031,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>
@@ -1044,6 +1044,166 @@
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXCRYPTOSSHAGENT-12668891">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>
<div class="card__section">
<div class="card__labels">
<div class="label label--medium">
<span class="label__text">medium severity</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:
min-document
</li>
<li class="card__meta__item">Introduced through:
argo-cd-ui@1.0.0, react-hot-loader@3.1.3 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>
react-hot-loader@3.1.3
<span class="list-paths__item__arrow"></span>
global@4.4.0
<span class="list-paths__item__arrow"></span>
min-document@2.19.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 Prototype Pollution via the <code>removeAttributeNS</code> function. An attacker can manipulate the prototype chain of JavaScript objects, potentially causing a denial-of-service attack by supplying malicious input that targets the <code>__proto__</code> property during namespace attribute removal.</p>
<p><strong>Notes</strong>:</p>
<p>This vulnerability is only exploitable if user input is passed without sanitization to the affected functions. The PoC has been validated as a theoretical vector, and a fixed version has been released.</p>
<h2 id="details">Details</h2>
<p>Prototype Pollution is a vulnerability affecting JavaScript. Prototype Pollution refers to the ability to inject properties into existing JavaScript language construct prototypes, such as objects. JavaScript allows all Object attributes to be altered, including their magical attributes such as <code>__proto__</code>, <code>constructor</code> and <code>prototype</code>. An attacker manipulates these attributes to overwrite, or pollute, a JavaScript application object prototype of the base object by injecting other values. Properties on the <code>Object.prototype</code> are then inherited by all the JavaScript objects through the prototype chain. When that happens, this leads to either denial of service by triggering JavaScript exceptions, or it tampers with the application source code to force the code path that the attacker injects, thereby leading to remote code execution.</p>
<p>There are two main ways in which the pollution of prototypes occurs:</p>
<ul>
<li><p>Unsafe <code>Object</code> recursive merge</p>
</li>
<li><p>Property definition by path</p>
</li>
</ul>
<h3 id="unsafe-object-recursive-merge">Unsafe Object recursive merge</h3>
<p>The logic of a vulnerable recursive merge function follows the following high-level model:</p>
<pre><code>merge (target, source)
foreach property of source
if property exists and is an object on both the target and the source
merge(target[property], source[property])
else
target[property] = source[property]
</code></pre>
<br>
<p>When the source object contains a property named <code>__proto__</code> defined with <code>Object.defineProperty()</code> , the condition that checks if the property exists and is an object on both the target and the source passes and the merge recurses with the target, being the prototype of <code>Object</code> and the source of <code>Object</code> as defined by the attacker. Properties are then copied on the <code>Object</code> prototype.</p>
<p>Clone operations are a special sub-class of unsafe recursive merges, which occur when a recursive merge is conducted on an empty object: <code>merge({},source)</code>.</p>
<p><code>lodash</code> and <code>Hoek</code> are examples of libraries susceptible to recursive merge attacks.</p>
<h3 id="property-definition-by-path">Property definition by path</h3>
<p>There are a few JavaScript libraries that use an API to define property values on an object based on a given path. The function that is generally affected contains this signature: <code>theFunction(object, path, value)</code></p>
<p>If the attacker can control the value of “path”, they can set this value to <code>__proto__.myValue</code>. <code>myValue</code> is then assigned to the prototype of the class of the object.</p>
<h2 id="types-of-attacks">Types of attacks</h2>
<p>There are a few methods by which Prototype Pollution can be manipulated:</p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Origin</th>
<th>Short description</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Denial of service (DoS)</strong></td>
<td>Client</td>
<td>This is the most likely attack. <br>DoS occurs when <code>Object</code> holds generic functions that are implicitly called for various operations (for example, <code>toString</code> and <code>valueOf</code>). <br> The attacker pollutes <code>Object.prototype.someattr</code> and alters its state to an unexpected value such as <code>Int</code> or <code>Object</code>. In this case, the code fails and is likely to cause a denial of service. <br><strong>For example:</strong> if an attacker pollutes <code>Object.prototype.toString</code> by defining it as an integer, if the codebase at any point was reliant on <code>someobject.toString()</code> it would fail.</td>
</tr>
<tr>
<td><strong>Remote Code Execution</strong></td>
<td>Client</td>
<td>Remote code execution is generally only possible in cases where the codebase evaluates a specific attribute of an object, and then executes that evaluation.<br><strong>For example:</strong> <code>eval(someobject.someattr)</code>. In this case, if the attacker pollutes <code>Object.prototype.someattr</code> they are likely to be able to leverage this in order to execute code.</td>
</tr>
<tr>
<td><strong>Property Injection</strong></td>
<td>Client</td>
<td>The attacker pollutes properties that the codebase relies on for their informative value, including security properties such as cookies or tokens.<br> <strong>For example:</strong> if a codebase checks privileges for <code>someuser.isAdmin</code>, then when the attacker pollutes <code>Object.prototype.isAdmin</code> and sets it to equal <code>true</code>, they can then achieve admin privileges.</td>
</tr>
</tbody></table>
<h2 id="affected-environments">Affected environments</h2>
<p>The following environments are susceptible to a Prototype Pollution attack:</p>
<ul>
<li><p>Application server</p>
</li>
<li><p>Web server</p>
</li>
<li><p>Web browser</p>
</li>
</ul>
<h2 id="how-to-prevent">How to prevent</h2>
<ol>
<li><p>Freeze the prototype— use <code>Object.freeze (Object.prototype)</code>.</p>
</li>
<li><p>Require schema validation of JSON input.</p>
</li>
<li><p>Avoid using unsafe recursive merge functions.</p>
</li>
<li><p>Consider using objects without prototypes (for example, <code>Object.create(null)</code>), breaking the prototype chain and preventing pollution.</p>
</li>
<li><p>As a best practice use <code>Map</code> instead of <code>Object</code>.</p>
</li>
</ol>
<h3 id="for-more-information-on-this-vulnerability-type">For more information on this vulnerability type:</h3>
<p><a href="https://github.com/HoLyVieR/prototype-pollution-nsec18/blob/master/paper/JavaScript_prototype_pollution_attack_in_NodeJS.pdf">Arteau, Oliver. “JavaScript prototype pollution attack in NodeJS application.” GitHub, 26 May 2018</a></p>
<h2 id="remediation">Remediation</h2>
<p>There is no fixed version for <code>min-document</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/Raynos/min-document/pull/55/commits/0d4e8192ef723fb869645256102a56ed922efd68">Github Commit</a></li>
<li><a href="https://github.com/Raynos/min-document/issues/54">GitHub Issue</a></li>
<li><a href="https://github.com/OrangeShieldInfos/PoCs/tree/main/JavaScript/prototype-pollution/CVE-2025-57352">POC</a></li>
<li><a href="https://github.com/Raynos/min-document/blob/bf7b69130a364b5c6fcb8e623bffe43054994c65/dom-element.js#L129">Vulnerable Code</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-JS-MINDOCUMENT-13045385">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">LGPL-3.0 license</h2>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:32:48 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:32:19 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -1063,7 +1063,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:32:56 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:32:26 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:33:03 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:32:32 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:33:23 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:32:54 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -737,7 +737,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:33:30 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:32:59 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:32:09 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:31:39 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:32:19 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:31:50 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -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="17 known vulnerabilities found in 110 vulnerable dependency paths.">
<meta name="description" content="18 known vulnerabilities found in 111 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">
@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:30:02 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:29:35 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -499,8 +499,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>17</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>110 vulnerable dependency paths</span></div>
<div class="meta-count"><span>18</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>111 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2085</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -867,7 +867,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>
@@ -2008,6 +2008,166 @@
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GITHUBCOMEXPRLANGEXPRCONF-9460818">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>
<div class="card__section">
<div class="card__labels">
<div class="label label--medium">
<span class="label__text">medium severity</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:
min-document
</li>
<li class="card__meta__item">Introduced through:
argo-cd-ui@1.0.0, react-hot-loader@3.1.3 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>
react-hot-loader@3.1.3
<span class="list-paths__item__arrow"></span>
global@4.4.0
<span class="list-paths__item__arrow"></span>
min-document@2.19.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 Prototype Pollution via the <code>removeAttributeNS</code> function. An attacker can manipulate the prototype chain of JavaScript objects, potentially causing a denial-of-service attack by supplying malicious input that targets the <code>__proto__</code> property during namespace attribute removal.</p>
<p><strong>Notes</strong>:</p>
<p>This vulnerability is only exploitable if user input is passed without sanitization to the affected functions. The PoC has been validated as a theoretical vector, and a fixed version has been released.</p>
<h2 id="details">Details</h2>
<p>Prototype Pollution is a vulnerability affecting JavaScript. Prototype Pollution refers to the ability to inject properties into existing JavaScript language construct prototypes, such as objects. JavaScript allows all Object attributes to be altered, including their magical attributes such as <code>__proto__</code>, <code>constructor</code> and <code>prototype</code>. An attacker manipulates these attributes to overwrite, or pollute, a JavaScript application object prototype of the base object by injecting other values. Properties on the <code>Object.prototype</code> are then inherited by all the JavaScript objects through the prototype chain. When that happens, this leads to either denial of service by triggering JavaScript exceptions, or it tampers with the application source code to force the code path that the attacker injects, thereby leading to remote code execution.</p>
<p>There are two main ways in which the pollution of prototypes occurs:</p>
<ul>
<li><p>Unsafe <code>Object</code> recursive merge</p>
</li>
<li><p>Property definition by path</p>
</li>
</ul>
<h3 id="unsafe-object-recursive-merge">Unsafe Object recursive merge</h3>
<p>The logic of a vulnerable recursive merge function follows the following high-level model:</p>
<pre><code>merge (target, source)
foreach property of source
if property exists and is an object on both the target and the source
merge(target[property], source[property])
else
target[property] = source[property]
</code></pre>
<br>
<p>When the source object contains a property named <code>__proto__</code> defined with <code>Object.defineProperty()</code> , the condition that checks if the property exists and is an object on both the target and the source passes and the merge recurses with the target, being the prototype of <code>Object</code> and the source of <code>Object</code> as defined by the attacker. Properties are then copied on the <code>Object</code> prototype.</p>
<p>Clone operations are a special sub-class of unsafe recursive merges, which occur when a recursive merge is conducted on an empty object: <code>merge({},source)</code>.</p>
<p><code>lodash</code> and <code>Hoek</code> are examples of libraries susceptible to recursive merge attacks.</p>
<h3 id="property-definition-by-path">Property definition by path</h3>
<p>There are a few JavaScript libraries that use an API to define property values on an object based on a given path. The function that is generally affected contains this signature: <code>theFunction(object, path, value)</code></p>
<p>If the attacker can control the value of “path”, they can set this value to <code>__proto__.myValue</code>. <code>myValue</code> is then assigned to the prototype of the class of the object.</p>
<h2 id="types-of-attacks">Types of attacks</h2>
<p>There are a few methods by which Prototype Pollution can be manipulated:</p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Origin</th>
<th>Short description</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Denial of service (DoS)</strong></td>
<td>Client</td>
<td>This is the most likely attack. <br>DoS occurs when <code>Object</code> holds generic functions that are implicitly called for various operations (for example, <code>toString</code> and <code>valueOf</code>). <br> The attacker pollutes <code>Object.prototype.someattr</code> and alters its state to an unexpected value such as <code>Int</code> or <code>Object</code>. In this case, the code fails and is likely to cause a denial of service. <br><strong>For example:</strong> if an attacker pollutes <code>Object.prototype.toString</code> by defining it as an integer, if the codebase at any point was reliant on <code>someobject.toString()</code> it would fail.</td>
</tr>
<tr>
<td><strong>Remote Code Execution</strong></td>
<td>Client</td>
<td>Remote code execution is generally only possible in cases where the codebase evaluates a specific attribute of an object, and then executes that evaluation.<br><strong>For example:</strong> <code>eval(someobject.someattr)</code>. In this case, if the attacker pollutes <code>Object.prototype.someattr</code> they are likely to be able to leverage this in order to execute code.</td>
</tr>
<tr>
<td><strong>Property Injection</strong></td>
<td>Client</td>
<td>The attacker pollutes properties that the codebase relies on for their informative value, including security properties such as cookies or tokens.<br> <strong>For example:</strong> if a codebase checks privileges for <code>someuser.isAdmin</code>, then when the attacker pollutes <code>Object.prototype.isAdmin</code> and sets it to equal <code>true</code>, they can then achieve admin privileges.</td>
</tr>
</tbody></table>
<h2 id="affected-environments">Affected environments</h2>
<p>The following environments are susceptible to a Prototype Pollution attack:</p>
<ul>
<li><p>Application server</p>
</li>
<li><p>Web server</p>
</li>
<li><p>Web browser</p>
</li>
</ul>
<h2 id="how-to-prevent">How to prevent</h2>
<ol>
<li><p>Freeze the prototype— use <code>Object.freeze (Object.prototype)</code>.</p>
</li>
<li><p>Require schema validation of JSON input.</p>
</li>
<li><p>Avoid using unsafe recursive merge functions.</p>
</li>
<li><p>Consider using objects without prototypes (for example, <code>Object.create(null)</code>), breaking the prototype chain and preventing pollution.</p>
</li>
<li><p>As a best practice use <code>Map</code> instead of <code>Object</code>.</p>
</li>
</ol>
<h3 id="for-more-information-on-this-vulnerability-type">For more information on this vulnerability type:</h3>
<p><a href="https://github.com/HoLyVieR/prototype-pollution-nsec18/blob/master/paper/JavaScript_prototype_pollution_attack_in_NodeJS.pdf">Arteau, Oliver. “JavaScript prototype pollution attack in NodeJS application.” GitHub, 26 May 2018</a></p>
<h2 id="remediation">Remediation</h2>
<p>There is no fixed version for <code>min-document</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/Raynos/min-document/pull/55/commits/0d4e8192ef723fb869645256102a56ed922efd68">Github Commit</a></li>
<li><a href="https://github.com/Raynos/min-document/issues/54">GitHub Issue</a></li>
<li><a href="https://github.com/OrangeShieldInfos/PoCs/tree/main/JavaScript/prototype-pollution/CVE-2025-57352">POC</a></li>
<li><a href="https://github.com/Raynos/min-document/blob/bf7b69130a364b5c6fcb8e623bffe43054994c65/dom-element.js#L129">Vulnerable Code</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-JS-MINDOCUMENT-13045385">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>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:30:12 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:29:44 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -1063,7 +1063,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:30:16 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:29:48 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:30:21 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:29:52 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:30:41 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:30:15 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -579,7 +579,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:30:46 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:30:19 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:29:31 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:29:03 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:29:41 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:29:14 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -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="10 known vulnerabilities found in 33 vulnerable dependency paths.">
<meta name="description" content="11 known vulnerabilities found in 34 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">
@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:27:36 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:27:05 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -499,8 +499,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>10</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>33 vulnerable dependency paths</span></div>
<div class="meta-count"><span>11</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>34 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2104</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -699,7 +699,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>
@@ -712,6 +712,166 @@
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXCRYPTOSSHAGENT-12668891">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>
<div class="card__section">
<div class="card__labels">
<div class="label label--medium">
<span class="label__text">medium severity</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:
min-document
</li>
<li class="card__meta__item">Introduced through:
argo-cd-ui@1.0.0, react-hot-loader@3.1.3 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>
react-hot-loader@3.1.3
<span class="list-paths__item__arrow"></span>
global@4.4.0
<span class="list-paths__item__arrow"></span>
min-document@2.19.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 Prototype Pollution via the <code>removeAttributeNS</code> function. An attacker can manipulate the prototype chain of JavaScript objects, potentially causing a denial-of-service attack by supplying malicious input that targets the <code>__proto__</code> property during namespace attribute removal.</p>
<p><strong>Notes</strong>:</p>
<p>This vulnerability is only exploitable if user input is passed without sanitization to the affected functions. The PoC has been validated as a theoretical vector, and a fixed version has been released.</p>
<h2 id="details">Details</h2>
<p>Prototype Pollution is a vulnerability affecting JavaScript. Prototype Pollution refers to the ability to inject properties into existing JavaScript language construct prototypes, such as objects. JavaScript allows all Object attributes to be altered, including their magical attributes such as <code>__proto__</code>, <code>constructor</code> and <code>prototype</code>. An attacker manipulates these attributes to overwrite, or pollute, a JavaScript application object prototype of the base object by injecting other values. Properties on the <code>Object.prototype</code> are then inherited by all the JavaScript objects through the prototype chain. When that happens, this leads to either denial of service by triggering JavaScript exceptions, or it tampers with the application source code to force the code path that the attacker injects, thereby leading to remote code execution.</p>
<p>There are two main ways in which the pollution of prototypes occurs:</p>
<ul>
<li><p>Unsafe <code>Object</code> recursive merge</p>
</li>
<li><p>Property definition by path</p>
</li>
</ul>
<h3 id="unsafe-object-recursive-merge">Unsafe Object recursive merge</h3>
<p>The logic of a vulnerable recursive merge function follows the following high-level model:</p>
<pre><code>merge (target, source)
foreach property of source
if property exists and is an object on both the target and the source
merge(target[property], source[property])
else
target[property] = source[property]
</code></pre>
<br>
<p>When the source object contains a property named <code>__proto__</code> defined with <code>Object.defineProperty()</code> , the condition that checks if the property exists and is an object on both the target and the source passes and the merge recurses with the target, being the prototype of <code>Object</code> and the source of <code>Object</code> as defined by the attacker. Properties are then copied on the <code>Object</code> prototype.</p>
<p>Clone operations are a special sub-class of unsafe recursive merges, which occur when a recursive merge is conducted on an empty object: <code>merge({},source)</code>.</p>
<p><code>lodash</code> and <code>Hoek</code> are examples of libraries susceptible to recursive merge attacks.</p>
<h3 id="property-definition-by-path">Property definition by path</h3>
<p>There are a few JavaScript libraries that use an API to define property values on an object based on a given path. The function that is generally affected contains this signature: <code>theFunction(object, path, value)</code></p>
<p>If the attacker can control the value of “path”, they can set this value to <code>__proto__.myValue</code>. <code>myValue</code> is then assigned to the prototype of the class of the object.</p>
<h2 id="types-of-attacks">Types of attacks</h2>
<p>There are a few methods by which Prototype Pollution can be manipulated:</p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Origin</th>
<th>Short description</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Denial of service (DoS)</strong></td>
<td>Client</td>
<td>This is the most likely attack. <br>DoS occurs when <code>Object</code> holds generic functions that are implicitly called for various operations (for example, <code>toString</code> and <code>valueOf</code>). <br> The attacker pollutes <code>Object.prototype.someattr</code> and alters its state to an unexpected value such as <code>Int</code> or <code>Object</code>. In this case, the code fails and is likely to cause a denial of service. <br><strong>For example:</strong> if an attacker pollutes <code>Object.prototype.toString</code> by defining it as an integer, if the codebase at any point was reliant on <code>someobject.toString()</code> it would fail.</td>
</tr>
<tr>
<td><strong>Remote Code Execution</strong></td>
<td>Client</td>
<td>Remote code execution is generally only possible in cases where the codebase evaluates a specific attribute of an object, and then executes that evaluation.<br><strong>For example:</strong> <code>eval(someobject.someattr)</code>. In this case, if the attacker pollutes <code>Object.prototype.someattr</code> they are likely to be able to leverage this in order to execute code.</td>
</tr>
<tr>
<td><strong>Property Injection</strong></td>
<td>Client</td>
<td>The attacker pollutes properties that the codebase relies on for their informative value, including security properties such as cookies or tokens.<br> <strong>For example:</strong> if a codebase checks privileges for <code>someuser.isAdmin</code>, then when the attacker pollutes <code>Object.prototype.isAdmin</code> and sets it to equal <code>true</code>, they can then achieve admin privileges.</td>
</tr>
</tbody></table>
<h2 id="affected-environments">Affected environments</h2>
<p>The following environments are susceptible to a Prototype Pollution attack:</p>
<ul>
<li><p>Application server</p>
</li>
<li><p>Web server</p>
</li>
<li><p>Web browser</p>
</li>
</ul>
<h2 id="how-to-prevent">How to prevent</h2>
<ol>
<li><p>Freeze the prototype— use <code>Object.freeze (Object.prototype)</code>.</p>
</li>
<li><p>Require schema validation of JSON input.</p>
</li>
<li><p>Avoid using unsafe recursive merge functions.</p>
</li>
<li><p>Consider using objects without prototypes (for example, <code>Object.create(null)</code>), breaking the prototype chain and preventing pollution.</p>
</li>
<li><p>As a best practice use <code>Map</code> instead of <code>Object</code>.</p>
</li>
</ol>
<h3 id="for-more-information-on-this-vulnerability-type">For more information on this vulnerability type:</h3>
<p><a href="https://github.com/HoLyVieR/prototype-pollution-nsec18/blob/master/paper/JavaScript_prototype_pollution_attack_in_NodeJS.pdf">Arteau, Oliver. “JavaScript prototype pollution attack in NodeJS application.” GitHub, 26 May 2018</a></p>
<h2 id="remediation">Remediation</h2>
<p>There is no fixed version for <code>min-document</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/Raynos/min-document/pull/55/commits/0d4e8192ef723fb869645256102a56ed922efd68">Github Commit</a></li>
<li><a href="https://github.com/Raynos/min-document/issues/54">GitHub Issue</a></li>
<li><a href="https://github.com/OrangeShieldInfos/PoCs/tree/main/JavaScript/prototype-pollution/CVE-2025-57352">POC</a></li>
<li><a href="https://github.com/Raynos/min-document/blob/bf7b69130a364b5c6fcb8e623bffe43054994c65/dom-element.js#L129">Vulnerable Code</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-JS-MINDOCUMENT-13045385">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>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:27:44 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:27:12 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -724,7 +724,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:27:48 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:27:16 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:27:55 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:27:21 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:28:15 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:27:42 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -579,7 +579,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:27:08 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:26:40 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:27:19 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:26:50 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -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="9 known vulnerabilities found in 32 vulnerable dependency paths.">
<meta name="description" content="10 known vulnerabilities found in 33 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">
@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:25:11 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:24:33 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -499,8 +499,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>9</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>32 vulnerable dependency paths</span></div>
<div class="meta-count"><span>10</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>33 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2115</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -624,7 +624,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>
@@ -637,6 +637,166 @@
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXCRYPTOSSHAGENT-12668891">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>
<div class="card__section">
<div class="card__labels">
<div class="label label--medium">
<span class="label__text">medium severity</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:
min-document
</li>
<li class="card__meta__item">Introduced through:
argo-cd-ui@1.0.0, react-hot-loader@3.1.3 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>
react-hot-loader@3.1.3
<span class="list-paths__item__arrow"></span>
global@4.4.0
<span class="list-paths__item__arrow"></span>
min-document@2.19.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 Prototype Pollution via the <code>removeAttributeNS</code> function. An attacker can manipulate the prototype chain of JavaScript objects, potentially causing a denial-of-service attack by supplying malicious input that targets the <code>__proto__</code> property during namespace attribute removal.</p>
<p><strong>Notes</strong>:</p>
<p>This vulnerability is only exploitable if user input is passed without sanitization to the affected functions. The PoC has been validated as a theoretical vector, and a fixed version has been released.</p>
<h2 id="details">Details</h2>
<p>Prototype Pollution is a vulnerability affecting JavaScript. Prototype Pollution refers to the ability to inject properties into existing JavaScript language construct prototypes, such as objects. JavaScript allows all Object attributes to be altered, including their magical attributes such as <code>__proto__</code>, <code>constructor</code> and <code>prototype</code>. An attacker manipulates these attributes to overwrite, or pollute, a JavaScript application object prototype of the base object by injecting other values. Properties on the <code>Object.prototype</code> are then inherited by all the JavaScript objects through the prototype chain. When that happens, this leads to either denial of service by triggering JavaScript exceptions, or it tampers with the application source code to force the code path that the attacker injects, thereby leading to remote code execution.</p>
<p>There are two main ways in which the pollution of prototypes occurs:</p>
<ul>
<li><p>Unsafe <code>Object</code> recursive merge</p>
</li>
<li><p>Property definition by path</p>
</li>
</ul>
<h3 id="unsafe-object-recursive-merge">Unsafe Object recursive merge</h3>
<p>The logic of a vulnerable recursive merge function follows the following high-level model:</p>
<pre><code>merge (target, source)
foreach property of source
if property exists and is an object on both the target and the source
merge(target[property], source[property])
else
target[property] = source[property]
</code></pre>
<br>
<p>When the source object contains a property named <code>__proto__</code> defined with <code>Object.defineProperty()</code> , the condition that checks if the property exists and is an object on both the target and the source passes and the merge recurses with the target, being the prototype of <code>Object</code> and the source of <code>Object</code> as defined by the attacker. Properties are then copied on the <code>Object</code> prototype.</p>
<p>Clone operations are a special sub-class of unsafe recursive merges, which occur when a recursive merge is conducted on an empty object: <code>merge({},source)</code>.</p>
<p><code>lodash</code> and <code>Hoek</code> are examples of libraries susceptible to recursive merge attacks.</p>
<h3 id="property-definition-by-path">Property definition by path</h3>
<p>There are a few JavaScript libraries that use an API to define property values on an object based on a given path. The function that is generally affected contains this signature: <code>theFunction(object, path, value)</code></p>
<p>If the attacker can control the value of “path”, they can set this value to <code>__proto__.myValue</code>. <code>myValue</code> is then assigned to the prototype of the class of the object.</p>
<h2 id="types-of-attacks">Types of attacks</h2>
<p>There are a few methods by which Prototype Pollution can be manipulated:</p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Origin</th>
<th>Short description</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Denial of service (DoS)</strong></td>
<td>Client</td>
<td>This is the most likely attack. <br>DoS occurs when <code>Object</code> holds generic functions that are implicitly called for various operations (for example, <code>toString</code> and <code>valueOf</code>). <br> The attacker pollutes <code>Object.prototype.someattr</code> and alters its state to an unexpected value such as <code>Int</code> or <code>Object</code>. In this case, the code fails and is likely to cause a denial of service. <br><strong>For example:</strong> if an attacker pollutes <code>Object.prototype.toString</code> by defining it as an integer, if the codebase at any point was reliant on <code>someobject.toString()</code> it would fail.</td>
</tr>
<tr>
<td><strong>Remote Code Execution</strong></td>
<td>Client</td>
<td>Remote code execution is generally only possible in cases where the codebase evaluates a specific attribute of an object, and then executes that evaluation.<br><strong>For example:</strong> <code>eval(someobject.someattr)</code>. In this case, if the attacker pollutes <code>Object.prototype.someattr</code> they are likely to be able to leverage this in order to execute code.</td>
</tr>
<tr>
<td><strong>Property Injection</strong></td>
<td>Client</td>
<td>The attacker pollutes properties that the codebase relies on for their informative value, including security properties such as cookies or tokens.<br> <strong>For example:</strong> if a codebase checks privileges for <code>someuser.isAdmin</code>, then when the attacker pollutes <code>Object.prototype.isAdmin</code> and sets it to equal <code>true</code>, they can then achieve admin privileges.</td>
</tr>
</tbody></table>
<h2 id="affected-environments">Affected environments</h2>
<p>The following environments are susceptible to a Prototype Pollution attack:</p>
<ul>
<li><p>Application server</p>
</li>
<li><p>Web server</p>
</li>
<li><p>Web browser</p>
</li>
</ul>
<h2 id="how-to-prevent">How to prevent</h2>
<ol>
<li><p>Freeze the prototype— use <code>Object.freeze (Object.prototype)</code>.</p>
</li>
<li><p>Require schema validation of JSON input.</p>
</li>
<li><p>Avoid using unsafe recursive merge functions.</p>
</li>
<li><p>Consider using objects without prototypes (for example, <code>Object.create(null)</code>), breaking the prototype chain and preventing pollution.</p>
</li>
<li><p>As a best practice use <code>Map</code> instead of <code>Object</code>.</p>
</li>
</ol>
<h3 id="for-more-information-on-this-vulnerability-type">For more information on this vulnerability type:</h3>
<p><a href="https://github.com/HoLyVieR/prototype-pollution-nsec18/blob/master/paper/JavaScript_prototype_pollution_attack_in_NodeJS.pdf">Arteau, Oliver. “JavaScript prototype pollution attack in NodeJS application.” GitHub, 26 May 2018</a></p>
<h2 id="remediation">Remediation</h2>
<p>There is no fixed version for <code>min-document</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/Raynos/min-document/pull/55/commits/0d4e8192ef723fb869645256102a56ed922efd68">Github Commit</a></li>
<li><a href="https://github.com/Raynos/min-document/issues/54">GitHub Issue</a></li>
<li><a href="https://github.com/OrangeShieldInfos/PoCs/tree/main/JavaScript/prototype-pollution/CVE-2025-57352">POC</a></li>
<li><a href="https://github.com/Raynos/min-document/blob/bf7b69130a364b5c6fcb8e623bffe43054994c65/dom-element.js#L129">Vulnerable Code</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-JS-MINDOCUMENT-13045385">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>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:25:18 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:24:40 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -724,7 +724,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>

View File

@@ -487,7 +487,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:25:23 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:24:44 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -0,0 +1,523 @@
<!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;
}
.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">November 2nd 2025, 12:24:56 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.2-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.2-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>

View File

@@ -487,16 +487,16 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">October 19th 2025, 12:25:53 am (UTC+00:00)</p>
<p class="timestamp">November 2nd 2025, 12:25:21 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.0-rc3/argoproj/argocd/Dockerfile (deb)</li>
<li class="paths">quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argo-cd/v3//usr/local/bin/argocd (gomodules)</li>
<li class="paths">quay.io/argoproj/argocd:v3.2.0-rc3//usr/local/bin/kustomize (gomodules)</li>
<li class="paths">quay.io/argoproj/argocd:v3.2.0-rc3/helm/v3//usr/local/bin/helm (gomodules)</li>
<li class="paths">quay.io/argoproj/argocd:v3.2.0-rc3/git-lfs/git-lfs//usr/bin/git-lfs (gomodules)</li>
<li class="paths">quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd/Dockerfile (deb)</li>
<li class="paths">quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argo-cd/v3//usr/local/bin/argocd (gomodules)</li>
<li class="paths">quay.io/argoproj/argocd:v3.2.0-rc4//usr/local/bin/kustomize (gomodules)</li>
<li class="paths">quay.io/argoproj/argocd:v3.2.0-rc4/helm/v3//usr/local/bin/helm (gomodules)</li>
<li class="paths">quay.io/argoproj/argocd:v3.2.0-rc4/git-lfs/git-lfs//usr/bin/git-lfs (gomodules)</li>
</ul>
</div>
@@ -525,7 +525,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
</li>
<li class="card__meta__item">
Package Manager: golang
@@ -579,7 +579,7 @@
</li>
</ul>
<h2 id="remediation">Remediation</h2>
<p>A fix was pushed into the <code>master</code> branch but not yet published.</p>
<p>Upgrade <code>golang.org/x/crypto/ssh/agent</code> to version 0.43.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/golang/crypto/commit/559e062ce8bfd6a39925294620b50906ca2a6f95">GitHub Commit</a></li>
@@ -607,7 +607,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -620,7 +620,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3 and tar@1.35+dfsg-3.1
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4 and tar@1.35+dfsg-3.1
</li>
</ul>
@@ -633,7 +633,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
tar@1.35+dfsg-3.1
@@ -642,7 +642,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
dpkg@1.22.18ubuntu2.2
<span class="list-paths__item__arrow"></span>
@@ -694,7 +694,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -707,7 +707,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3 and pam/libpam0g@1.5.3-7ubuntu4.4
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4 and pam/libpam0g@1.5.3-7ubuntu4.4
</li>
</ul>
@@ -720,7 +720,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
pam/libpam0g@1.5.3-7ubuntu4.4
@@ -729,7 +729,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
util-linux@2.40.2-14ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -740,7 +740,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
util-linux/login@1:4.16.0-2+really2.40.2-14ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -751,7 +751,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
apt@3.0.0
<span class="list-paths__item__arrow"></span>
@@ -766,7 +766,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
apt@3.0.0
<span class="list-paths__item__arrow"></span>
@@ -783,7 +783,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
apt@3.0.0
<span class="list-paths__item__arrow"></span>
@@ -802,7 +802,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
pam/libpam-modules-bin@1.5.3-7ubuntu4.4
@@ -811,7 +811,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
apt@3.0.0
<span class="list-paths__item__arrow"></span>
@@ -828,7 +828,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
pam/libpam-modules@1.5.3-7ubuntu4.4
@@ -837,7 +837,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
pam/libpam-runtime@1.5.3-7ubuntu4.4
<span class="list-paths__item__arrow"></span>
@@ -848,7 +848,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
util-linux@2.40.2-14ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -859,7 +859,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
util-linux/login@1:4.16.0-2+really2.40.2-14ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -870,7 +870,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
apt@3.0.0
<span class="list-paths__item__arrow"></span>
@@ -885,7 +885,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
pam/libpam-runtime@1.5.3-7ubuntu4.4
@@ -894,7 +894,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
util-linux@2.40.2-14ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -905,7 +905,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
util-linux/login@1:4.16.0-2+really2.40.2-14ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -969,7 +969,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
</li>
<li class="card__meta__item">
Package Manager: golang
@@ -1031,7 +1031,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
</li>
<li class="card__meta__item">
Package Manager: golang
@@ -1093,7 +1093,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
</li>
<li class="card__meta__item">
Package Manager: golang
@@ -1155,7 +1155,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/helm/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/helm
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/helm/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/helm
</li>
<li class="card__meta__item">
Package Manager: golang
@@ -1217,7 +1217,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
</li>
<li class="card__meta__item">
Package Manager: golang
@@ -1279,7 +1279,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argo-cd/v3 <span class="list-paths__item__arrow"></span> /usr/local/bin/argocd
</li>
<li class="card__meta__item">
Package Manager: golang
@@ -1341,7 +1341,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -1355,7 +1355,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3, git@1:2.48.1-0ubuntu1.1 and others
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4, git@1:2.48.1-0ubuntu1.1 and others
</li>
</ul>
@@ -1367,7 +1367,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
git@1:2.48.1-0ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -1378,7 +1378,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
git@1:2.48.1-0ubuntu1.1
@@ -1387,7 +1387,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
git-lfs@3.6.1-1
<span class="list-paths__item__arrow"></span>
@@ -1436,7 +1436,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -1449,7 +1449,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3 and shadow/login.defs@1:4.16.0-7ubuntu1
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4 and shadow/login.defs@1:4.16.0-7ubuntu1
</li>
</ul>
@@ -1462,7 +1462,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
shadow/login.defs@1:4.16.0-7ubuntu1
@@ -1471,7 +1471,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
util-linux/login@1:4.16.0-2+really2.40.2-14ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -1482,7 +1482,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
apt@3.0.0
<span class="list-paths__item__arrow"></span>
@@ -1497,7 +1497,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
shadow/passwd@1:4.16.0-7ubuntu1
@@ -1506,7 +1506,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
openssh/openssh-client@1:9.9p1-3ubuntu3.2
<span class="list-paths__item__arrow"></span>
@@ -1517,7 +1517,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
apt@3.0.0
<span class="list-paths__item__arrow"></span>
@@ -1569,7 +1569,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -1582,7 +1582,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3 and patch@2.7.6-7build3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4 and patch@2.7.6-7build3
</li>
</ul>
@@ -1595,7 +1595,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
patch@2.7.6-7build3
@@ -1646,7 +1646,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -1659,7 +1659,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3 and patch@2.7.6-7build3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4 and patch@2.7.6-7build3
</li>
</ul>
@@ -1672,7 +1672,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
patch@2.7.6-7build3
@@ -1718,7 +1718,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -1731,7 +1731,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3 and libgcrypt20@1.11.0-6ubuntu1
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4 and libgcrypt20@1.11.0-6ubuntu1
</li>
</ul>
@@ -1744,7 +1744,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
libgcrypt20@1.11.0-6ubuntu1
@@ -1753,7 +1753,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/dirmngr@2.4.4-2ubuntu23.1
<span class="list-paths__item__arrow"></span>
@@ -1764,7 +1764,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/gpg@2.4.4-2ubuntu23.1
<span class="list-paths__item__arrow"></span>
@@ -1775,7 +1775,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/gpg-agent@2.4.4-2ubuntu23.1
<span class="list-paths__item__arrow"></span>
@@ -1786,7 +1786,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
apt@3.0.0
<span class="list-paths__item__arrow"></span>
@@ -1799,7 +1799,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/gpg@2.4.4-2ubuntu23.1
<span class="list-paths__item__arrow"></span>
@@ -1854,7 +1854,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -1867,7 +1867,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3 and gnupg2/gpgv@2.4.4-2ubuntu23.1
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4 and gnupg2/gpgv@2.4.4-2ubuntu23.1
</li>
</ul>
@@ -1880,7 +1880,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/gpgv@2.4.4-2ubuntu23.1
@@ -1889,7 +1889,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
apt@3.0.0
<span class="list-paths__item__arrow"></span>
@@ -1900,7 +1900,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/dirmngr@2.4.4-2ubuntu23.1
<span class="list-paths__item__arrow"></span>
@@ -1911,7 +1911,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/gpg-agent@2.4.4-2ubuntu23.1
<span class="list-paths__item__arrow"></span>
@@ -1922,7 +1922,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/gpg@2.4.4-2ubuntu23.1
<span class="list-paths__item__arrow"></span>
@@ -1933,7 +1933,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/dirmngr@2.4.4-2ubuntu23.1
@@ -1942,7 +1942,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/gpg@2.4.4-2ubuntu23.1
@@ -1951,7 +1951,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
gnupg2/gpg-agent@2.4.4-2ubuntu23.1
@@ -2002,7 +2002,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -2015,7 +2015,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3 and glibc/libc-bin@2.41-6ubuntu1.2
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4 and glibc/libc-bin@2.41-6ubuntu1.2
</li>
</ul>
@@ -2028,7 +2028,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
glibc/libc-bin@2.41-6ubuntu1.2
@@ -2037,7 +2037,7 @@
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
glibc/libc6@2.41-6ubuntu1.2
@@ -2085,7 +2085,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -2099,7 +2099,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3, git@1:2.48.1-0ubuntu1.1 and others
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4, git@1:2.48.1-0ubuntu1.1 and others
</li>
</ul>
@@ -2111,7 +2111,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
git@1:2.48.1-0ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -2176,7 +2176,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -2190,7 +2190,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3, git@1:2.48.1-0ubuntu1.1 and others
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4, git@1:2.48.1-0ubuntu1.1 and others
</li>
</ul>
@@ -2202,7 +2202,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
git@1:2.48.1-0ubuntu1.1
<span class="list-paths__item__arrow"></span>
@@ -2259,7 +2259,7 @@
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
Manifest file: quay.io/argoproj/argocd:v3.2.0-rc4/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:25.04
@@ -2272,7 +2272,7 @@
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v3.2.0-rc3 and coreutils@9.5-1ubuntu1.25.04.2
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4 and coreutils@9.5-1ubuntu1.25.04.2
</li>
</ul>
@@ -2285,7 +2285,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.0-rc3
docker-image|quay.io/argoproj/argocd@v3.2.0-rc4
<span class="list-paths__item__arrow"></span>
coreutils@9.5-1ubuntu1.25.04.2

View File

@@ -51,6 +51,7 @@ argocd admin repo generate-spec REPOURL [flags]
```
--bearer-token string bearer token to the Git BitBucket Data Center repository
--depth int Specify a custom depth for git clone operations. Unless specified, a full clone is performed using the depth of 0
--enable-lfs enable git-lfs (Large File Support) on this repository
--enable-oci enable helm-oci (Helm OCI-Based Repository) (only valid for helm type repositories)
--force-http-basic-auth whether to force use of basic auth when connecting repository via HTTP

View File

@@ -62,6 +62,7 @@ argocd repo add REPOURL [flags]
```
--bearer-token string bearer token to the Git BitBucket Data Center repository
--depth int Specify a custom depth for git clone operations. Unless specified, a full clone is performed using the depth of 0
--enable-lfs enable git-lfs (Large File Support) on this repository
--enable-oci enable helm-oci (Helm OCI-Based Repository) (only valid for helm type repositories)
--force-http-basic-auth whether to force use of basic auth when connecting repository via HTTP

View File

@@ -31,14 +31,14 @@ The following configuration options are available for Kustomize:
* `commonLabels` is a string map of additional labels
* `labelWithoutSelector` is a boolean value which defines if the common label(s) should be applied to resource selectors. It also excludes common labels from templates unless `labelIncludeTemplates` is set to true.
* `labelIncludeTemplates` is a boolean value which defines if the common label(s) should be applied to resource templates.
* `forceCommonLabels` is a boolean value which defines if it's allowed to override existing labels
* `commonAnnotations` is a string map of additional annotations
* `namespace` is a Kubernetes resources namespace
* `forceCommonAnnotations` is a boolean value which defines if it's allowed to override existing annotations
* `commonAnnotationsEnvsubst` is a boolean value which enables env variables substitution in annotation values
* `patches` is a list of Kustomize patches that supports inline updates
* `components` is a list of Kustomize components
* `ignoreMissingComponents` prevents kustomize from failing when components do not exist locally by not appending them to kustomization file
* `forceCommonLabels` is a boolean value. When true, Argo CD passes --force to kustomize edit add label, allowing an existing commonLabels/labels entry in kustomization.yaml to be replaced. When false, generation fails if the label key already exists.
* `forceCommonAnnotations` is a boolean value. When true, Argo CD passes --force to kustomize edit add annotation, allowing an existing commonAnnotations entry in kustomization.yaml to be replaced. When false, generation fails if the annotation key already exists.
To use Kustomize with an overlay, point your path to the overlay.

View File

@@ -29,6 +29,17 @@ argocd app set guestbook -p ingress.hosts[0]=guestbook.myclusterurl
The `argocd app set` [command](./commands/argocd_app_set.md) supports more tool-specific flags such as `--kustomize-image`, `--jsonnet-ext-var-str`, etc.
You can also specify overrides directly in the source field on the application spec. Read more about supported options in the corresponding tool [documentation](./application_sources.md).
## Overrides in Multi-Source Applications
For multi-source applications, Argo CD allows you to override parameters for a specific source using the `--source-position` flag.
Each source in the application spec is indexed starting from `0`.
For example, to override a parameter in the **second source (index 1)** of a multi-source app:
```bash
argocd app set my-app --source-position 1 -p replicaCount=2
```
## When To Use Overrides?
The following are situations where parameter overrides would be useful:

File diff suppressed because it is too large Load Diff

View File

@@ -891,10 +891,8 @@ func TestServerSideDiff(t *testing.T) {
manager := "argocd-controller"
dryRunner := mocks.NewServerSideDryRunner(t)
dryRunner.On("Run", mock.Anything, mock.AnythingOfType("*unstructured.Unstructured"), manager).
Return(func(_ context.Context, _ *unstructured.Unstructured, _ string) (string, error) {
return predictedLive, nil
})
dryRunner.EXPECT().Run(mock.Anything, mock.AnythingOfType("*unstructured.Unstructured"), manager).
Return(predictedLive, nil)
opts := []Option{
WithGVKParser(gvkParser),
WithManager(manager),

View File

@@ -1,48 +1,16 @@
// Code generated by mockery v2.38.0. DO NOT EDIT.
// Code generated by mockery; DO NOT EDIT.
// github.com/vektra/mockery
// template: testify
package mocks
import (
context "context"
"context"
mock "github.com/stretchr/testify/mock"
unstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// ServerSideDryRunner is an autogenerated mock type for the ServerSideDryRunner type
type ServerSideDryRunner struct {
mock.Mock
}
// Run provides a mock function with given fields: ctx, obj, manager
func (_m *ServerSideDryRunner) Run(ctx context.Context, obj *unstructured.Unstructured, manager string) (string, error) {
ret := _m.Called(ctx, obj, manager)
if len(ret) == 0 {
panic("no return value specified for Run")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, string) (string, error)); ok {
return rf(ctx, obj, manager)
}
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, string) string); ok {
r0 = rf(ctx, obj, manager)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(context.Context, *unstructured.Unstructured, string) error); ok {
r1 = rf(ctx, obj, manager)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// NewServerSideDryRunner creates a new instance of ServerSideDryRunner. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewServerSideDryRunner(t interface {
@@ -56,3 +24,88 @@ func NewServerSideDryRunner(t interface {
return mock
}
// ServerSideDryRunner is an autogenerated mock type for the ServerSideDryRunner type
type ServerSideDryRunner struct {
mock.Mock
}
type ServerSideDryRunner_Expecter struct {
mock *mock.Mock
}
func (_m *ServerSideDryRunner) EXPECT() *ServerSideDryRunner_Expecter {
return &ServerSideDryRunner_Expecter{mock: &_m.Mock}
}
// Run provides a mock function for the type ServerSideDryRunner
func (_mock *ServerSideDryRunner) Run(ctx context.Context, obj *unstructured.Unstructured, manager string) (string, error) {
ret := _mock.Called(ctx, obj, manager)
if len(ret) == 0 {
panic("no return value specified for Run")
}
var r0 string
var r1 error
if returnFunc, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, string) (string, error)); ok {
return returnFunc(ctx, obj, manager)
}
if returnFunc, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, string) string); ok {
r0 = returnFunc(ctx, obj, manager)
} else {
r0 = ret.Get(0).(string)
}
if returnFunc, ok := ret.Get(1).(func(context.Context, *unstructured.Unstructured, string) error); ok {
r1 = returnFunc(ctx, obj, manager)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ServerSideDryRunner_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run'
type ServerSideDryRunner_Run_Call struct {
*mock.Call
}
// Run is a helper method to define mock.On call
// - ctx context.Context
// - obj *unstructured.Unstructured
// - manager string
func (_e *ServerSideDryRunner_Expecter) Run(ctx interface{}, obj interface{}, manager interface{}) *ServerSideDryRunner_Run_Call {
return &ServerSideDryRunner_Run_Call{Call: _e.mock.On("Run", ctx, obj, manager)}
}
func (_c *ServerSideDryRunner_Run_Call) Run(run func(ctx context.Context, obj *unstructured.Unstructured, manager string)) *ServerSideDryRunner_Run_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
arg0 = args[0].(context.Context)
}
var arg1 *unstructured.Unstructured
if args[1] != nil {
arg1 = args[1].(*unstructured.Unstructured)
}
var arg2 string
if args[2] != nil {
arg2 = args[2].(string)
}
run(
arg0,
arg1,
arg2,
)
})
return _c
}
func (_c *ServerSideDryRunner_Run_Call) Return(s string, err error) *ServerSideDryRunner_Run_Call {
_c.Call.Return(s, err)
return _c
}
func (_c *ServerSideDryRunner_Run_Call) RunAndReturn(run func(ctx context.Context, obj *unstructured.Unstructured, manager string) (string, error)) *ServerSideDryRunner_Run_Call {
_c.Call.Return(run)
return _c
}

6
go.mod
View File

@@ -13,14 +13,14 @@ require (
github.com/TomOnTime/utfutil v1.0.0
github.com/alicebob/miniredis/v2 v2.35.0
github.com/argoproj/gitops-engine v0.7.1-0.20250908182407-97ad5b59a627
github.com/argoproj/notifications-engine v0.4.1-0.20250908182349-da04400446ff
github.com/argoproj/notifications-engine v0.5.1-0.20251028200032-58cdc54685b4
github.com/argoproj/pkg v0.13.6
github.com/argoproj/pkg/v2 v2.0.1
github.com/aws/aws-sdk-go v1.55.7
github.com/bmatcuk/doublestar/v4 v4.9.1
github.com/bombsimon/logrusr/v4 v4.1.0
github.com/bradleyfalzon/ghinstallation/v2 v2.17.0
github.com/casbin/casbin/v2 v2.128.0
github.com/casbin/casbin/v2 v2.131.0
github.com/casbin/govaluate v1.10.0
github.com/cespare/xxhash/v2 v2.3.0
github.com/chainguard-dev/git-urls v1.0.2
@@ -87,7 +87,7 @@ require (
github.com/stretchr/testify v1.11.1
github.com/valyala/fasttemplate v1.2.2
github.com/yuin/gopher-lua v1.1.1
gitlab.com/gitlab-org/api/client-go v0.157.0
gitlab.com/gitlab-org/api/client-go v0.157.1
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0
go.opentelemetry.io/otel v1.38.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0

12
go.sum
View File

@@ -113,8 +113,8 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE=
github.com/argoproj/notifications-engine v0.4.1-0.20250908182349-da04400446ff h1:pGGAeHIktPuYCRl1Z540XdxPFnedqyUhJK4VgpyJZfY=
github.com/argoproj/notifications-engine v0.4.1-0.20250908182349-da04400446ff/go.mod h1:d1RazGXWvKRFv9//rg4MRRR7rbvbE7XLgTSMT5fITTE=
github.com/argoproj/notifications-engine v0.5.1-0.20251028200032-58cdc54685b4 h1:3RZiddNmnwG+RMqjIcGoDIJTK5gq7TKDYI0mhGiHERk=
github.com/argoproj/notifications-engine v0.5.1-0.20251028200032-58cdc54685b4/go.mod h1:d1RazGXWvKRFv9//rg4MRRR7rbvbE7XLgTSMT5fITTE=
github.com/argoproj/pkg v0.13.6 h1:36WPD9MNYECHcO1/R1pj6teYspiK7uMQLCgLGft2abM=
github.com/argoproj/pkg v0.13.6/go.mod h1:I698DoJBKuvNFaixh4vFl2C88cNIT1WS7KCbz5ewyF8=
github.com/argoproj/pkg/v2 v2.0.1 h1:O/gCETzB/3+/hyFL/7d/VM/6pSOIRWIiBOTb2xqAHvc=
@@ -173,8 +173,8 @@ github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdb
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/casbin/casbin/v2 v2.128.0 h1:761dLmXLy/ZNSckAITvpUZ8VdrxARyIlwmdafHzRb7Y=
github.com/casbin/casbin/v2 v2.128.0/go.mod h1:iAwqzcYzJtAK5QWGT2uRl9WfRxXyKFBG1AZuhk2NAQg=
github.com/casbin/casbin/v2 v2.131.0 h1:JWkedeOpvxkBE7iIrWqf2RSMOU/xmxsxgbQ8QzsmGiQ=
github.com/casbin/casbin/v2 v2.131.0/go.mod h1:FmcfntdXLTcYXv/hxgNntcRPqAbwOG9xsism0yXT+18=
github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/casbin/govaluate v1.10.0 h1:ffGw51/hYH3w3rZcxO/KcaUIDOLP84w7nsidMVgaDG0=
github.com/casbin/govaluate v1.10.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
@@ -918,8 +918,8 @@ github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
gitlab.com/gitlab-org/api/client-go v0.157.0 h1:B+/Ku1ek3V/MInR/SmvL4FOqE0YYx51u7lBVYIHC2ic=
gitlab.com/gitlab-org/api/client-go v0.157.0/go.mod h1:CQVoxjEswJZeXft4Mi+H+OF1MVrpNVF6m4xvlPTQ2J4=
gitlab.com/gitlab-org/api/client-go v0.157.1 h1:oYbOYk0A2Q+bc1drw8fikSvgi5GImQ9Cj0L0zkZ+PfY=
gitlab.com/gitlab-org/api/client-go v0.157.1/go.mod h1:CQVoxjEswJZeXft4Mi+H+OF1MVrpNVF6m4xvlPTQ2J4=
go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=

File diff suppressed because it is too large Load Diff

View File

@@ -1916,6 +1916,9 @@ message Repository {
// InsecureOCIForceHttp specifies whether the connection to the repository uses TLS at _all_. If true, no TLS. This flag is applicable for OCI repos only.
optional bool insecureOCIForceHttp = 26;
// Depth specifies the depth for shallow clones. A value of 0 or omitting the field indicates a full clone.
optional int64 depth = 27;
}
// A RepositoryCertificate is either SSH known hosts entry or TLS certificate

View File

@@ -114,6 +114,8 @@ type Repository struct {
BearerToken string `json:"bearerToken,omitempty" protobuf:"bytes,25,opt,name=bearerToken"`
// InsecureOCIForceHttp specifies whether the connection to the repository uses TLS at _all_. If true, no TLS. This flag is applicable for OCI repos only.
InsecureOCIForceHttp bool `json:"insecureOCIForceHttp,omitempty" protobuf:"bytes,26,opt,name=insecureOCIForceHttp"` //nolint:revive //FIXME(var-naming)
// Depth specifies the depth for shallow clones. A value of 0 or omitting the field indicates a full clone.
Depth int64 `json:"depth,omitempty" protobuf:"bytes,27,opt,name=depth"`
}
// IsInsecure returns true if the repository has been configured to skip server verification or set to HTTP only
@@ -330,6 +332,7 @@ func (repo *Repository) CopySettingsFrom(source *Repository) {
repo.InsecureIgnoreHostKey = source.InsecureIgnoreHostKey
repo.Insecure = source.Insecure
repo.InheritedCreds = source.InheritedCreds
repo.Depth = source.Depth
}
}

View File

@@ -247,7 +247,7 @@ func (s *Service) ListApps(ctx context.Context, q *apiclient.ListAppsRequest) (*
defer s.metricsServer.DecPendingRepoRequest(q.Repo.Repo)
closer, err := s.repoLock.Lock(gitClient.Root(), commitSHA, true, func() (goio.Closer, error) {
return s.checkoutRevision(gitClient, commitSHA, s.initConstants.SubmoduleEnabled)
return s.checkoutRevision(gitClient, commitSHA, s.initConstants.SubmoduleEnabled, q.Repo.Depth)
})
if err != nil {
return nil, fmt.Errorf("error acquiring repository lock: %w", err)
@@ -449,7 +449,7 @@ func (s *Service) runRepoOperation(
})
}
closer, err := s.repoLock.Lock(gitClient.Root(), revision, settings.allowConcurrent, func() (goio.Closer, error) {
return s.checkoutRevision(gitClient, revision, s.initConstants.SubmoduleEnabled)
return s.checkoutRevision(gitClient, revision, s.initConstants.SubmoduleEnabled, repo.Depth)
})
if err != nil {
return err
@@ -834,7 +834,7 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA,
return
}
closer, err := s.repoLock.Lock(gitClient.Root(), referencedCommitSHA, true, func() (goio.Closer, error) {
return s.checkoutRevision(gitClient, referencedCommitSHA, s.initConstants.SubmoduleEnabled)
return s.checkoutRevision(gitClient, referencedCommitSHA, s.initConstants.SubmoduleEnabled, q.Repo.Depth)
})
if err != nil {
log.Errorf("failed to acquire lock for referenced source %s", normalizedRepoURL)
@@ -2435,7 +2435,7 @@ func (s *Service) GetRevisionMetadata(_ context.Context, q *apiclient.RepoServer
defer s.metricsServer.DecPendingRepoRequest(q.Repo.Repo)
closer, err := s.repoLock.Lock(gitClient.Root(), q.Revision, true, func() (goio.Closer, error) {
return s.checkoutRevision(gitClient, q.Revision, s.initConstants.SubmoduleEnabled)
return s.checkoutRevision(gitClient, q.Revision, s.initConstants.SubmoduleEnabled, q.Repo.Depth)
})
if err != nil {
return nil, fmt.Errorf("error acquiring repo lock: %w", err)
@@ -2658,9 +2658,9 @@ func directoryPermissionInitializer(rootPath string) goio.Closer {
// checkoutRevision is a convenience function to initialize a repo, fetch, and checkout a revision
// Returns the 40 character commit SHA after the checkout has been performed
func (s *Service) checkoutRevision(gitClient git.Client, revision string, submoduleEnabled bool) (goio.Closer, error) {
func (s *Service) checkoutRevision(gitClient git.Client, revision string, submoduleEnabled bool, depth int64) (goio.Closer, error) {
closer := s.gitRepoInitializer(gitClient.Root())
err := checkoutRevision(gitClient, revision, submoduleEnabled)
err := checkoutRevision(gitClient, revision, submoduleEnabled, depth)
if err != nil {
s.metricsServer.IncGitFetchFail(gitClient.Root(), revision)
}
@@ -2692,7 +2692,7 @@ func fetch(gitClient git.Client, targetRevisions []string) error {
return nil
}
// Fetching with no revision first. Fetching with an explicit version can cause repo bloat. https://github.com/argoproj/argo-cd/issues/8845
err := gitClient.Fetch("")
err := gitClient.Fetch("", 0)
if err != nil {
return err
}
@@ -2703,7 +2703,7 @@ func fetch(gitClient git.Client, targetRevisions []string) error {
log.Infof("Failed to fetch revision %s: %v", revision, err)
log.Infof("Fallback to fetching specific revision %s. ref might not have been in the default refspec fetched.", revision)
if err := gitClient.Fetch(revision); err != nil {
if err := gitClient.Fetch(revision, 0); err != nil {
return status.Errorf(codes.Internal, "Failed to fetch revision %s: %v", revision, err)
}
}
@@ -2711,7 +2711,7 @@ func fetch(gitClient git.Client, targetRevisions []string) error {
return nil
}
func checkoutRevision(gitClient git.Client, revision string, submoduleEnabled bool) error {
func checkoutRevision(gitClient git.Client, revision string, submoduleEnabled bool, depth int64) error {
err := gitClient.Init()
if err != nil {
return status.Errorf(codes.Internal, "Failed to initialize git repo: %v", err)
@@ -2725,8 +2725,13 @@ func checkoutRevision(gitClient git.Client, revision string, submoduleEnabled bo
// Fetching can be skipped if the revision is already present locally.
if !revisionPresent {
// Fetching with no revision first. Fetching with an explicit version can cause repo bloat. https://github.com/argoproj/argo-cd/issues/8845
err = gitClient.Fetch("")
if depth > 0 {
err = gitClient.Fetch(revision, depth)
} else {
// Fetching with no revision first. Fetching with an explicit version can cause repo bloat. https://github.com/argoproj/argo-cd/issues/8845
err = gitClient.Fetch("", depth)
}
if err != nil {
return status.Errorf(codes.Internal, "Failed to fetch default: %v", err)
}
@@ -2738,8 +2743,7 @@ func checkoutRevision(gitClient git.Client, revision string, submoduleEnabled bo
// for the given revision, try explicitly fetching it.
log.Infof("Failed to checkout revision %s: %v", revision, err)
log.Infof("Fallback to fetching specific revision %s. ref might not have been in the default refspec fetched.", revision)
err = gitClient.Fetch(revision)
err = gitClient.Fetch(revision, depth)
if err != nil {
return status.Errorf(codes.Internal, "Failed to checkout revision %s: %v", revision, err)
}
@@ -2886,7 +2890,7 @@ func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequ
// cache miss, generate the results
closer, err := s.repoLock.Lock(gitClient.Root(), revision, true, func() (goio.Closer, error) {
return s.checkoutRevision(gitClient, revision, request.GetSubmoduleEnabled())
return s.checkoutRevision(gitClient, revision, request.GetSubmoduleEnabled(), repo.Depth)
})
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to checkout git repo %s with revision %s pattern %s: %v", repo.Repo, revision, gitPath, err)
@@ -2968,7 +2972,7 @@ func (s *Service) GetGitDirectories(_ context.Context, request *apiclient.GitDir
// cache miss, generate the results
closer, err := s.repoLock.Lock(gitClient.Root(), revision, true, func() (goio.Closer, error) {
return s.checkoutRevision(gitClient, revision, request.GetSubmoduleEnabled())
return s.checkoutRevision(gitClient, revision, request.GetSubmoduleEnabled(), repo.Depth)
})
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to checkout git repo %s with revision %s: %v", repo.Repo, revision, err)
@@ -3060,7 +3064,7 @@ func (s *Service) UpdateRevisionForPaths(_ context.Context, request *apiclient.U
defer s.metricsServer.DecPendingRepoRequest(repo.Repo)
closer, err := s.repoLock.Lock(gitClient.Root(), revision, true, func() (goio.Closer, error) {
return s.checkoutRevision(gitClient, revision, false)
return s.checkoutRevision(gitClient, revision, false, 0)
})
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to checkout git repo %s with revision %s: %v", repo.Repo, revision, err)

View File

@@ -109,42 +109,41 @@ func newServiceWithMocks(t *testing.T, root string, signed bool) (*Service, *git
panic(err)
}
return newServiceWithOpt(t, func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, ociClient *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Init").Return(nil)
gitClient.On("IsRevisionPresent", mock.Anything).Return(false)
gitClient.On("Fetch", mock.Anything).Return(nil)
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.On("LsRemote", mock.Anything).Return(mock.Anything, nil)
gitClient.On("CommitSHA").Return(mock.Anything, nil)
gitClient.On("Root").Return(root)
gitClient.On("IsAnnotatedTag").Return(false)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().IsRevisionPresent(mock.Anything).Return(false)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().LsRemote(mock.Anything).Return(mock.Anything, nil)
gitClient.EXPECT().CommitSHA().Return(mock.Anything, nil)
gitClient.EXPECT().Root().Return(root)
gitClient.EXPECT().IsAnnotatedTag(mock.Anything).Return(false)
if signed {
gitClient.On("VerifyCommitSignature", mock.Anything).Return(testSignature, nil)
gitClient.EXPECT().VerifyCommitSignature(mock.Anything).Return(testSignature, nil)
} else {
gitClient.On("VerifyCommitSignature", mock.Anything).Return("", nil)
gitClient.EXPECT().VerifyCommitSignature(mock.Anything).Return("", nil)
}
chart := "my-chart"
oobChart := "out-of-bounds-chart"
version := "1.1.0"
helmClient.On("GetIndex", mock.AnythingOfType("bool"), mock.Anything).Return(&helm.Index{Entries: map[string]helm.Entries{
helmClient.EXPECT().GetIndex(mock.AnythingOfType("bool"), mock.Anything).Return(&helm.Index{Entries: map[string]helm.Entries{
chart: {{Version: "1.0.0"}, {Version: version}},
oobChart: {{Version: "1.0.0"}, {Version: version}},
}}, nil)
helmClient.On("GetTags", mock.Anything, mock.Anything).Return(nil, nil)
helmClient.On("ExtractChart", chart, version, false, int64(0), false).Return("./testdata/my-chart", utilio.NopCloser, nil)
helmClient.On("ExtractChart", oobChart, version, false, int64(0), false).Return("./testdata2/out-of-bounds-chart", utilio.NopCloser, nil)
helmClient.On("CleanChartCache", chart, version).Return(nil)
helmClient.On("CleanChartCache", oobChart, version).Return(nil)
helmClient.On("DependencyBuild").Return(nil)
helmClient.EXPECT().GetTags(mock.Anything, mock.Anything).Return(nil, nil)
helmClient.EXPECT().ExtractChart(chart, version, false, int64(0), false).Return("./testdata/my-chart", utilio.NopCloser, nil)
helmClient.EXPECT().ExtractChart(oobChart, version, false, int64(0), false).Return("./testdata2/out-of-bounds-chart", utilio.NopCloser, nil)
helmClient.EXPECT().CleanChartCache(chart, version).Return(nil)
helmClient.EXPECT().CleanChartCache(oobChart, version).Return(nil)
ociClient.On("GetTags", mock.Anything, mock.Anything).Return(nil)
ociClient.On("ResolveRevision", mock.Anything, mock.Anything, mock.Anything).Return("", nil)
ociClient.On("Extract", mock.Anything, mock.Anything).Return("./testdata/my-chart", utilio.NopCloser, nil)
ociClient.EXPECT().GetTags(mock.Anything, mock.Anything).Return(nil, nil)
ociClient.EXPECT().ResolveRevision(mock.Anything, mock.Anything, mock.Anything).Return("", nil)
ociClient.EXPECT().Extract(mock.Anything, mock.Anything).Return("./testdata/my-chart", utilio.NopCloser, nil)
paths.On("Add", mock.Anything, mock.Anything).Return(root, nil)
paths.On("GetPath", mock.Anything).Return(root, nil)
paths.On("GetPathIfExists", mock.Anything).Return(root, nil)
paths.On("GetPaths").Return(map[string]string{"fake-nonce": root})
paths.EXPECT().Add(mock.Anything, mock.Anything).Return()
paths.EXPECT().GetPath(mock.Anything).Return(root, nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(root)
paths.EXPECT().GetPaths().Return(map[string]string{"fake-nonce": root})
}, root)
}
@@ -197,15 +196,15 @@ func newServiceWithCommitSHA(t *testing.T, root, revision string) *Service {
}
service, gitClient, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Init").Return(nil)
gitClient.On("IsRevisionPresent", mock.Anything).Return(false)
gitClient.On("Fetch", mock.Anything).Return(nil)
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.On("LsRemote", revision).Return(revision, revisionErr)
gitClient.On("CommitSHA").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("Root").Return(root)
paths.On("GetPath", mock.Anything).Return(root, nil)
paths.On("GetPathIfExists", mock.Anything).Return(root, nil)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().IsRevisionPresent(mock.Anything).Return(false)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().LsRemote(revision).Return(revision, revisionErr)
gitClient.EXPECT().CommitSHA().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.EXPECT().Root().Return(root)
paths.EXPECT().GetPath(mock.Anything).Return(root, nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(root)
}, root)
service.newGitClient = func(_ string, _ string, _ git.Creds, _ bool, _ bool, _ string, _ string, _ ...git.ClientOpts) (client git.Client, e error) {
@@ -400,7 +399,7 @@ func TestGenerateManifests_EmptyCache(t *testing.T) {
ExternalDeletes: 1,
})
gitMocks.AssertCalled(t, "LsRemote", mock.Anything)
gitMocks.AssertCalled(t, "Fetch", mock.Anything)
gitMocks.AssertCalled(t, "Fetch", mock.Anything, mock.Anything)
}
// Test that when Generate manifest is called with a source that is ref only it does not try to generate manifests or hit the manifest cache
@@ -1778,7 +1777,7 @@ func TestGetRevisionMetadata(t *testing.T) {
service, gitClient, _ := newServiceWithMocks(t, "../..", false)
now := time.Now()
gitClient.On("RevisionMetadata", mock.Anything).Return(&git.RevisionMetadata{
gitClient.EXPECT().RevisionMetadata(mock.Anything).Return(&git.RevisionMetadata{
Message: "test",
Author: "author",
Date: now,
@@ -3174,10 +3173,10 @@ func TestCheckoutRevisionCanGetNonstandardRefs(t *testing.T) {
pullSha, err := gitClient.LsRemote("refs/pull/123/head")
require.NoError(t, err)
err = checkoutRevision(gitClient, "does-not-exist", false)
err = checkoutRevision(gitClient, "does-not-exist", false, 0)
require.Error(t, err)
err = checkoutRevision(gitClient, pullSha, false)
err = checkoutRevision(gitClient, pullSha, false, 0)
require.NoError(t, err)
}
@@ -3185,11 +3184,11 @@ func TestCheckoutRevisionPresentSkipFetch(t *testing.T) {
revision := "0123456789012345678901234567890123456789"
gitClient := &gitmocks.Client{}
gitClient.On("Init").Return(nil)
gitClient.On("IsRevisionPresent", revision).Return(true)
gitClient.On("Checkout", revision, mock.Anything).Return("", nil)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().IsRevisionPresent(revision).Return(true)
gitClient.EXPECT().Checkout(revision, mock.Anything).Return("", nil)
err := checkoutRevision(gitClient, revision, false)
err := checkoutRevision(gitClient, revision, false, 0)
require.NoError(t, err)
}
@@ -3197,12 +3196,12 @@ func TestCheckoutRevisionNotPresentCallFetch(t *testing.T) {
revision := "0123456789012345678901234567890123456789"
gitClient := &gitmocks.Client{}
gitClient.On("Init").Return(nil)
gitClient.On("IsRevisionPresent", revision).Return(false)
gitClient.On("Fetch", "").Return(nil)
gitClient.On("Checkout", revision, mock.Anything).Return("", nil)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().IsRevisionPresent(revision).Return(false)
gitClient.EXPECT().Fetch("", mock.Anything).Return(nil)
gitClient.EXPECT().Checkout(revision, mock.Anything).Return("", nil)
err := checkoutRevision(gitClient, revision, false)
err := checkoutRevision(gitClient, revision, false, 0)
require.NoError(t, err)
}
@@ -3211,12 +3210,12 @@ func TestFetch(t *testing.T) {
revision2 := "abcdefabcdefabcdefabcdefabcdefabcdefabcd"
gitClient := &gitmocks.Client{}
gitClient.On("Init").Return(nil)
gitClient.On("IsRevisionPresent", revision1).Once().Return(true)
gitClient.On("IsRevisionPresent", revision2).Once().Return(false)
gitClient.On("Fetch", "").Return(nil)
gitClient.On("IsRevisionPresent", revision1).Once().Return(true)
gitClient.On("IsRevisionPresent", revision2).Once().Return(true)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().IsRevisionPresent(revision1).Once().Return(true)
gitClient.EXPECT().IsRevisionPresent(revision2).Once().Return(false)
gitClient.EXPECT().Fetch("", mock.Anything).Return(nil)
gitClient.EXPECT().IsRevisionPresent(revision1).Once().Return(true)
gitClient.EXPECT().IsRevisionPresent(revision2).Once().Return(true)
err := fetch(gitClient, []string{revision1, revision2})
require.NoError(t, err)
@@ -3608,11 +3607,11 @@ func TestErrorGetGitDirectories(t *testing.T) {
}, want: nil, wantErr: assert.Error},
{name: "InvalidResolveRevision", fields: fields{service: func() *Service {
s, _, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.On("LsRemote", mock.Anything).Return("", errors.New("ah error"))
gitClient.On("Root").Return(root)
paths.On("GetPath", mock.Anything).Return(".", nil)
paths.On("GetPathIfExists", mock.Anything).Return(".", nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().LsRemote(mock.Anything).Return("", errors.New("ah error"))
gitClient.EXPECT().Root().Return(root)
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(".")
}, ".")
return s
}()}, args: args{
@@ -3625,12 +3624,12 @@ func TestErrorGetGitDirectories(t *testing.T) {
}, want: nil, wantErr: assert.Error},
{name: "ErrorVerifyCommit", fields: fields{service: func() *Service {
s, _, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.On("LsRemote", mock.Anything).Return("", errors.New("ah error"))
gitClient.On("VerifyCommitSignature", mock.Anything).Return("", fmt.Errorf("revision %s is not signed", "sadfsadf"))
gitClient.On("Root").Return(root)
paths.On("GetPath", mock.Anything).Return(".", nil)
paths.On("GetPathIfExists", mock.Anything).Return(".", nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().LsRemote(mock.Anything).Return("", errors.New("ah error"))
gitClient.EXPECT().VerifyCommitSignature(mock.Anything).Return("", fmt.Errorf("revision %s is not signed", "sadfsadf"))
gitClient.EXPECT().Root().Return(root)
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(".")
}, ".")
return s
}()}, args: args{
@@ -3659,14 +3658,14 @@ func TestGetGitDirectories(t *testing.T) {
// test not using the cache
root := "./testdata/git-files-dirs"
s, _, cacheMocks := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Init").Return(nil)
gitClient.On("IsRevisionPresent", mock.Anything).Return(false)
gitClient.On("Fetch", mock.Anything).Return(nil)
gitClient.On("Checkout", mock.Anything, mock.Anything).Once().Return("", nil)
gitClient.On("LsRemote", "HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("Root").Return(root)
paths.On("GetPath", mock.Anything).Return(root, nil)
paths.On("GetPathIfExists", mock.Anything).Return(root, nil)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().IsRevisionPresent(mock.Anything).Return(false)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Once().Return("", nil)
gitClient.EXPECT().LsRemote("HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.EXPECT().Root().Return(root)
paths.EXPECT().GetPath(mock.Anything).Return(root, nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(root)
}, root)
dirRequest := &apiclient.GitDirectoriesRequest{
Repo: &v1alpha1.Repository{Repo: "a-url.com"},
@@ -3692,14 +3691,14 @@ func TestGetGitDirectoriesWithHiddenDirSupported(t *testing.T) {
// test not using the cache
root := "./testdata/git-files-dirs"
s, _, cacheMocks := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Init").Return(nil)
gitClient.On("IsRevisionPresent", mock.Anything).Return(false)
gitClient.On("Fetch", mock.Anything).Return(nil)
gitClient.On("Checkout", mock.Anything, mock.Anything).Once().Return("", nil)
gitClient.On("LsRemote", "HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("Root").Return(root)
paths.On("GetPath", mock.Anything).Return(root, nil)
paths.On("GetPathIfExists", mock.Anything).Return(root, nil)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().IsRevisionPresent(mock.Anything).Return(false)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Once().Return("", nil)
gitClient.EXPECT().LsRemote("HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.EXPECT().Root().Return(root)
paths.EXPECT().GetPath(mock.Anything).Return(root, nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(root)
}, root)
s.initConstants.IncludeHiddenDirectories = true
dirRequest := &apiclient.GitDirectoriesRequest{
@@ -3750,11 +3749,11 @@ func TestErrorGetGitFiles(t *testing.T) {
}, want: nil, wantErr: assert.Error},
{name: "InvalidResolveRevision", fields: fields{service: func() *Service {
s, _, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.On("LsRemote", mock.Anything).Return("", errors.New("ah error"))
gitClient.On("Root").Return(root)
paths.On("GetPath", mock.Anything).Return(".", nil)
paths.On("GetPathIfExists", mock.Anything).Return(".", nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().LsRemote(mock.Anything).Return("", errors.New("ah error"))
gitClient.EXPECT().Root().Return(root)
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(".")
}, ".")
return s
}()}, args: args{
@@ -3786,15 +3785,15 @@ func TestGetGitFiles(t *testing.T) {
}
root := ""
s, _, cacheMocks := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Init").Return(nil)
gitClient.On("IsRevisionPresent", mock.Anything).Return(false)
gitClient.On("Fetch", mock.Anything).Return(nil)
gitClient.On("Checkout", mock.Anything, mock.Anything).Once().Return("", nil)
gitClient.On("LsRemote", "HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("Root").Return(root)
gitClient.On("LsFiles", mock.Anything, mock.Anything).Once().Return(files, nil)
paths.On("GetPath", mock.Anything).Return(root, nil)
paths.On("GetPathIfExists", mock.Anything).Return(root, nil)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().IsRevisionPresent(mock.Anything).Return(false)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Return(nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Once().Return("", nil)
gitClient.EXPECT().LsRemote("HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.EXPECT().Root().Return(root)
gitClient.EXPECT().LsFiles(mock.Anything, mock.Anything).Once().Return(files, nil)
paths.EXPECT().GetPath(mock.Anything).Return(root, nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(root)
}, root)
filesRequest := &apiclient.GitFilesRequest{
Repo: &v1alpha1.Repository{Repo: "a-url.com"},
@@ -3853,11 +3852,11 @@ func TestErrorUpdateRevisionForPaths(t *testing.T) {
}, want: nil, wantErr: assert.Error},
{name: "InvalidResolveRevision", fields: fields{service: func() *Service {
s, _, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.On("LsRemote", mock.Anything).Return("", errors.New("ah error"))
gitClient.On("Root").Return(root)
paths.On("GetPath", mock.Anything).Return(".", nil)
paths.On("GetPathIfExists", mock.Anything).Return(".", nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().LsRemote(mock.Anything).Return("", errors.New("ah error"))
gitClient.EXPECT().Root().Return(root)
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(".")
}, ".")
return s
}()}, args: args{
@@ -3871,12 +3870,12 @@ func TestErrorUpdateRevisionForPaths(t *testing.T) {
}, want: nil, wantErr: assert.Error},
{name: "InvalidResolveSyncedRevision", fields: fields{service: func() *Service {
s, _, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.On("LsRemote", "HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("LsRemote", mock.Anything).Return("", errors.New("ah error"))
gitClient.On("Root").Return(root)
paths.On("GetPath", mock.Anything).Return(".", nil)
paths.On("GetPathIfExists", mock.Anything).Return(".", nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().LsRemote("HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.EXPECT().LsRemote(mock.Anything).Return("", errors.New("ah error"))
gitClient.EXPECT().Root().Return(root)
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(".")
}, ".")
return s
}()}, args: args{
@@ -3924,7 +3923,7 @@ func TestUpdateRevisionForPaths(t *testing.T) {
}{
{name: "NoPathAbort", fields: func() fields {
s, _, c := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, _ *iomocks.TempPaths) {
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
}, ".")
return fields{
service: s,
@@ -3939,11 +3938,11 @@ func TestUpdateRevisionForPaths(t *testing.T) {
}, want: &apiclient.UpdateRevisionForPathsResponse{}, wantErr: assert.NoError},
{name: "SameResolvedRevisionAbort", fields: func() fields {
s, _, c := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.On("LsRemote", "HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("LsRemote", "SYNCEDHEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
paths.On("GetPath", mock.Anything).Return(".", nil)
paths.On("GetPathIfExists", mock.Anything).Return(".", nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().LsRemote("HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.EXPECT().LsRemote("SYNCEDHEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(".")
}, ".")
return fields{
service: s,
@@ -3962,20 +3961,20 @@ func TestUpdateRevisionForPaths(t *testing.T) {
}, wantErr: assert.NoError},
{name: "ChangedFilesDoNothing", fields: func() fields {
s, _, c := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Init").Return(nil)
gitClient.On("Fetch", mock.Anything).Once().Return(nil)
gitClient.On("IsRevisionPresent", "632039659e542ed7de0c170a4fcc1c571b288fc0").Once().Return(false)
gitClient.On("Checkout", "632039659e542ed7de0c170a4fcc1c571b288fc0", mock.Anything).Once().Return("", nil)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Once().Return(nil)
gitClient.EXPECT().IsRevisionPresent("632039659e542ed7de0c170a4fcc1c571b288fc0").Once().Return(false)
gitClient.EXPECT().Checkout("632039659e542ed7de0c170a4fcc1c571b288fc0", mock.Anything).Once().Return("", nil)
// fetch
gitClient.On("IsRevisionPresent", "1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(false)
gitClient.On("Fetch", mock.Anything).Once().Return(nil)
gitClient.On("IsRevisionPresent", "1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(true)
gitClient.On("LsRemote", "HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("LsRemote", "SYNCEDHEAD").Once().Return("1e67a504d03def3a6a1125d934cb511680f72555", nil)
paths.On("GetPath", mock.Anything).Return(".", nil)
paths.On("GetPathIfExists", mock.Anything).Return(".", nil)
gitClient.On("Root").Return("")
gitClient.On("ChangedFiles", mock.Anything, mock.Anything).Return([]string{"app.yaml"}, nil)
gitClient.EXPECT().IsRevisionPresent("1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(false)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Once().Return(nil)
gitClient.EXPECT().IsRevisionPresent("1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(true)
gitClient.EXPECT().LsRemote("HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.EXPECT().LsRemote("SYNCEDHEAD").Once().Return("1e67a504d03def3a6a1125d934cb511680f72555", nil)
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(".")
gitClient.EXPECT().Root().Return("")
gitClient.EXPECT().ChangedFiles(mock.Anything, mock.Anything).Return([]string{"app.yaml"}, nil)
}, ".")
return fields{
service: s,
@@ -3995,20 +3994,20 @@ func TestUpdateRevisionForPaths(t *testing.T) {
}, wantErr: assert.NoError},
{name: "NoChangesUpdateCache", fields: func() fields {
s, _, c := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Init").Return(nil)
gitClient.On("Fetch", mock.Anything).Once().Return(nil)
gitClient.On("IsRevisionPresent", "632039659e542ed7de0c170a4fcc1c571b288fc0").Once().Return(false)
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.On("IsRevisionPresent", "1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(false)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Once().Return(nil)
gitClient.EXPECT().IsRevisionPresent("632039659e542ed7de0c170a4fcc1c571b288fc0").Once().Return(false)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().IsRevisionPresent("1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(false)
// fetch
gitClient.On("Fetch", mock.Anything).Once().Return(nil)
gitClient.On("IsRevisionPresent", "1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(true)
gitClient.On("LsRemote", "HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("LsRemote", "SYNCEDHEAD").Once().Return("1e67a504d03def3a6a1125d934cb511680f72555", nil)
paths.On("GetPath", mock.Anything).Return(".", nil)
paths.On("GetPathIfExists", mock.Anything).Return(".", nil)
gitClient.On("Root").Return("")
gitClient.On("ChangedFiles", mock.Anything, mock.Anything).Return([]string{}, nil)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Once().Return(nil)
gitClient.EXPECT().IsRevisionPresent("1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(true)
gitClient.EXPECT().LsRemote("HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.EXPECT().LsRemote("SYNCEDHEAD").Once().Return("1e67a504d03def3a6a1125d934cb511680f72555", nil)
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(".")
gitClient.EXPECT().Root().Return("")
gitClient.EXPECT().ChangedFiles(mock.Anything, mock.Anything).Return([]string{}, nil)
}, ".")
return fields{
service: s,
@@ -4037,19 +4036,19 @@ func TestUpdateRevisionForPaths(t *testing.T) {
}},
{name: "NoChangesHelmMultiSourceUpdateCache", fields: func() fields {
s, _, c := newServiceWithOpt(t, func(gitClient *gitmocks.Client, _ *helmmocks.Client, _ *ocimocks.Client, paths *iomocks.TempPaths) {
gitClient.On("Init").Return(nil)
gitClient.On("IsRevisionPresent", "632039659e542ed7de0c170a4fcc1c571b288fc0").Once().Return(false)
gitClient.On("Fetch", mock.Anything).Once().Return(nil)
gitClient.On("Checkout", mock.Anything, mock.Anything).Return("", nil)
gitClient.EXPECT().Init().Return(nil)
gitClient.EXPECT().IsRevisionPresent("632039659e542ed7de0c170a4fcc1c571b288fc0").Once().Return(false)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Once().Return(nil)
gitClient.EXPECT().Checkout(mock.Anything, mock.Anything).Return("", nil)
// fetch
gitClient.On("IsRevisionPresent", "1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(true)
gitClient.On("Fetch", mock.Anything).Once().Return(nil)
gitClient.On("LsRemote", "HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.On("LsRemote", "SYNCEDHEAD").Once().Return("1e67a504d03def3a6a1125d934cb511680f72555", nil)
paths.On("GetPath", mock.Anything).Return(".", nil)
paths.On("GetPathIfExists", mock.Anything).Return(".", nil)
gitClient.On("Root").Return("")
gitClient.On("ChangedFiles", mock.Anything, mock.Anything).Return([]string{}, nil)
gitClient.EXPECT().IsRevisionPresent("1e67a504d03def3a6a1125d934cb511680f72555").Once().Return(true)
gitClient.EXPECT().Fetch(mock.Anything, mock.Anything).Once().Return(nil)
gitClient.EXPECT().LsRemote("HEAD").Once().Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
gitClient.EXPECT().LsRemote("SYNCEDHEAD").Once().Return("1e67a504d03def3a6a1125d934cb511680f72555", nil)
paths.EXPECT().GetPath(mock.Anything).Return(".", nil)
paths.EXPECT().GetPathIfExists(mock.Anything).Return(".")
gitClient.EXPECT().Root().Return("")
gitClient.EXPECT().ChangedFiles(mock.Anything, mock.Anything).Return([]string{}, nil)
}, ".")
return fields{
service: s,
@@ -4307,7 +4306,7 @@ func TestVerifyCommitSignature(t *testing.T) {
t.Run("VerifyCommitSignature with valid signature", func(t *testing.T) {
t.Setenv("ARGOCD_GPG_ENABLED", "true")
mockGitClient := &gitmocks.Client{}
mockGitClient.On("VerifyCommitSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
mockGitClient.EXPECT().VerifyCommitSignature(mock.Anything).
Return(testSignature, nil)
err := verifyCommitSignature(true, mockGitClient, "abcd1234", repo)
require.NoError(t, err)
@@ -4316,7 +4315,7 @@ func TestVerifyCommitSignature(t *testing.T) {
t.Run("VerifyCommitSignature with invalid signature", func(t *testing.T) {
t.Setenv("ARGOCD_GPG_ENABLED", "true")
mockGitClient := &gitmocks.Client{}
mockGitClient.On("VerifyCommitSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
mockGitClient.EXPECT().VerifyCommitSignature(mock.Anything).
Return("", nil)
err := verifyCommitSignature(true, mockGitClient, "abcd1234", repo)
assert.EqualError(t, err, "revision abcd1234 is not signed")
@@ -4325,7 +4324,7 @@ func TestVerifyCommitSignature(t *testing.T) {
t.Run("VerifyCommitSignature with unknown signature", func(t *testing.T) {
t.Setenv("ARGOCD_GPG_ENABLED", "true")
mockGitClient := &gitmocks.Client{}
mockGitClient.On("VerifyCommitSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
mockGitClient.EXPECT().VerifyCommitSignature(mock.Anything).
Return("", errors.New("UNKNOWN signature: gpg: Unknown signature from ABCDEFGH"))
err := verifyCommitSignature(true, mockGitClient, "abcd1234", repo)
assert.EqualError(t, err, "UNKNOWN signature: gpg: Unknown signature from ABCDEFGH")
@@ -4334,7 +4333,7 @@ func TestVerifyCommitSignature(t *testing.T) {
t.Run("VerifyCommitSignature with error verifying signature", func(t *testing.T) {
t.Setenv("ARGOCD_GPG_ENABLED", "true")
mockGitClient := &gitmocks.Client{}
mockGitClient.On("VerifyCommitSignature", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
mockGitClient.EXPECT().VerifyCommitSignature(mock.Anything).
Return("", errors.New("error verifying signature of commit 'abcd1234' in repo 'https://github.com/example/repo.git': failed to verify signature"))
err := verifyCommitSignature(true, mockGitClient, "abcd1234", repo)
assert.EqualError(t, err, "error verifying signature of commit 'abcd1234' in repo 'https://github.com/example/repo.git': failed to verify signature")

View File

@@ -0,0 +1,39 @@
local hs = {}
local healthy = false
local degraded = false
local suspended = false
if obj.status ~= nil then
if obj.status.conditions ~= nil then
for i, condition in ipairs(obj.status.conditions) do
if condition.status == "False" and condition.type == "Ready" then
hs.message = condition.message
degraded = true
end
if condition.status == "True" and condition.type == "Ready" then
hs.message = condition.message
healthy = true
end
if condition.status == "True" and condition.type == "Paused" then
hs.message = condition.message
suspended = true
end
if condition.status == "Unknown" and condition.type == "Ready" then
hs.message = condition.message
degraded = true
end
end
end
end
if degraded == true then
hs.status = "Degraded"
return hs
elseif healthy == true and suspended == false then
hs.status = "Healthy"
return hs
elseif healthy == true and suspended == true then
hs.status = "Suspended"
return hs
end
hs.status = "Progressing"
hs.message = "Waiting for ScaledJob"
return hs

View File

@@ -0,0 +1,21 @@
tests:
- healthStatus:
status: Progressing
message: "Waiting for ScaledJob"
inputPath: testdata/keda-progressing.yaml
- healthStatus:
status: Degraded
message: "Triggers defined in ScaledJob are not working correctly"
inputPath: testdata/keda-degraded.yaml
- healthStatus:
status: Healthy
message: "ScaledJob is defined correctly and is ready to scaling"
inputPath: testdata/keda-healthy.yaml
- healthStatus:
status: Degraded
message: "Some triggers defined in ScaledJob are not working correctly"
inputPath: testdata/keda-unknown.yaml
- healthStatus:
status: Suspended
message: "ScaledJob is paused"
inputPath: testdata/keda-suspended.yaml

View File

@@ -0,0 +1,57 @@
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
annotations:
finalizers:
- finalizer.keda.sh
name: keda
namespace: keda
resourceVersion: '157163'
uid: 9a6b7c4f-c35b-46ca-a801-ee5cb515ce0a
spec:
jobTargetRef:
backoffLimit: 1
template:
metadata:
creationTimestamp: null
spec:
containers:
- command:
- sleep
- '10'
envFrom:
- secretRef:
name: scaledjob-conditions-test-secret
image: docker.io/library/busybox
imagePullPolicy: IfNotPresent
name: sleeper
resources: {}
restartPolicy: Never
maxReplicaCount: 5
pollingInterval: 5
rollout: {}
scalingStrategy: {}
triggers:
- metadata:
hostFromEnv: RabbitApiHost
mode: QueueLength
queueName: not-existing-queue
value: '1'
type: rabbitmq
status:
authenticationsTypes: ''
conditions:
- message: Triggers defined in ScaledJob are not working correctly
reason: TriggerError
status: 'False'
type: Ready
- message: Scaling is not performed because triggers are not active
reason: ScalerNotActive
status: 'False'
type: Active
- status: Unknown
type: Fallback
- status: 'False'
type: Paused
triggersTypes: rabbitmq

View File

@@ -0,0 +1,57 @@
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
annotations:
finalizers:
- finalizer.keda.sh
name: keda
namespace: keda
resourceVersion: '157477'
uid: 9a6b7c4f-c35b-46ca-a801-ee5cb515ce0a
spec:
jobTargetRef:
backoffLimit: 1
template:
metadata:
creationTimestamp: null
spec:
containers:
- command:
- sleep
- '10'
envFrom:
- secretRef:
name: scaledjob-conditions-test-secret
image: docker.io/library/busybox
imagePullPolicy: IfNotPresent
name: sleeper
resources: {}
restartPolicy: Never
maxReplicaCount: 5
pollingInterval: 5
rollout: {}
scalingStrategy: {}
triggers:
- metadata:
hostFromEnv: RabbitApiHost
mode: QueueLength
queueName: hello
value: '1'
type: rabbitmq
status:
authenticationsTypes: ''
conditions:
- message: ScaledJob is defined correctly and is ready to scaling
reason: ScaledJobReady
status: 'True'
type: Ready
- message: Scaling is performed because triggers are active
reason: ScalerActive
status: 'True'
type: Active
- status: Unknown
type: Fallback
- status: 'False'
type: Paused
triggersTypes: rabbitmq

View File

@@ -0,0 +1,49 @@
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
annotations:
finalizers:
- finalizer.keda.sh
name: keda
namespace: keda
resourceVersion: '159237'
uid: 9a6b7c4f-c35b-46ca-a801-ee5cb515ce0a
spec:
jobTargetRef:
backoffLimit: 1
template:
metadata:
creationTimestamp: null
spec:
containers:
- command:
- sleep
- '10'
envFrom:
- secretRef:
name: scaledjob-conditions-test-secret
image: docker.io/library/busybox
imagePullPolicy: IfNotPresent
name: sleeper
resources: {}
restartPolicy: Never
maxReplicaCount: 5
pollingInterval: 5
rollout: {}
scalingStrategy: {}
triggers:
- metadata:
hostFromEnv: RabbitApiHost
mode: QueueLength
queueName: hello
value: '1'
type: rabbitmq
status:
authenticationsTypes: ''
conditions:
- message: Waiting for ScaledJob
reason: Running
status: 'True'
type: Running
triggersTypes: rabbitmq

View File

@@ -0,0 +1,59 @@
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
annotations:
autoscaling.keda.sh/paused: 'true'
finalizers:
- finalizer.keda.sh
name: keda
namespace: keda
resourceVersion: '157163'
uid: 9a6b7c4f-c35b-46ca-a801-ee5cb515ce0a
spec:
jobTargetRef:
backoffLimit: 1
template:
metadata:
creationTimestamp: null
spec:
containers:
- command:
- sleep
- '10'
envFrom:
- secretRef:
name: scaledjob-conditions-test-secret
image: docker.io/library/busybox
imagePullPolicy: IfNotPresent
name: sleeper
resources: {}
restartPolicy: Never
maxReplicaCount: 5
pollingInterval: 5
rollout: {}
scalingStrategy: {}
triggers:
- metadata:
hostFromEnv: RabbitApiHost
mode: QueueLength
queueName: hello
value: '1'
type: rabbitmq
status:
authenticationsTypes: ''
conditions:
- message: ScaledJob is paused, skipping reconcile loop
reason: ScaledJobReady
status: 'True'
type: Ready
- message: Scaling is not performed because triggers are not active
reason: ScalerNotActive
status: 'False'
type: Active
- status: Unknown
type: Fallback
- message: ScaledJob is paused
reason: ScaledJobPaused
status: 'True'
type: Paused
triggersTypes: rabbitmq

View File

@@ -0,0 +1,63 @@
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
annotations:
finalizers:
- finalizer.keda.sh
name: keda
namespace: keda
resourceVersion: '158276'
uid: 9a6b7c4f-c35b-46ca-a801-ee5cb515ce0a
spec:
jobTargetRef:
backoffLimit: 1
template:
metadata:
creationTimestamp: null
spec:
containers:
- command:
- sleep
- '10'
envFrom:
- secretRef:
name: scaledjob-conditions-test-secret
image: docker.io/library/busybox
imagePullPolicy: IfNotPresent
name: sleeper
resources: {}
restartPolicy: Never
maxReplicaCount: 5
pollingInterval: 5
rollout: {}
scalingStrategy: {}
triggers:
- metadata:
hostFromEnv: RabbitApiHost
mode: QueueLength
queueName: hello
value: '1'
type: rabbitmq
- metadata:
hostFromEnv: RabbitApiHost
mode: QueueLength
queueName: not-existing-queue
value: '1'
type: rabbitmq
status:
authenticationsTypes: ''
conditions:
- message: Some triggers defined in ScaledJob are not working correctly
reason: PartialTriggerError
status: Unknown
type: Ready
- message: Scaling is performed because triggers are active
reason: ScalerActive
status: 'True'
type: Active
- status: Unknown
type: Fallback
- status: 'False'
type: Paused
triggersTypes: rabbitmq

View File

@@ -1771,7 +1771,8 @@ func (s *Server) ManagedResources(ctx context.Context, q *application.ResourcesQ
return s.cache.GetAppManagedResources(a.InstanceName(s.ns), &items)
})
if err != nil {
return nil, fmt.Errorf("error getting cached app managed resources: %w", err)
log.Warnf("error getting cached app managed resources for %s/%s, cache unavailable, returning empty managed resources: %v", a.Namespace, a.Name, err)
return &application.ManagedResourcesResponse{Items: []*v1alpha1.ResourceDiff{}}, nil
}
res := &application.ManagedResourcesResponse{}
for i := range items {

Some files were not shown because too many files have changed in this diff Show More