mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-16 21:38:48 +01:00
Compare commits
22 Commits
renovate/m
...
crenshaw-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19b19fda8d | ||
|
|
b7691b2167 | ||
|
|
21ae489589 | ||
|
|
e58bdf2f87 | ||
|
|
7a09f69ad6 | ||
|
|
1b08fd1004 | ||
|
|
0a93e5701f | ||
|
|
5072fb7136 | ||
|
|
b91c191a34 | ||
|
|
fe727c8fc9 | ||
|
|
fe4ab01cba | ||
|
|
4ea276860c | ||
|
|
f26533ab37 | ||
|
|
c2f611f8cd | ||
|
|
ef48aa9c37 | ||
|
|
1b4fde1986 | ||
|
|
ca84c31a46 | ||
|
|
f5eaae73a2 | ||
|
|
a2f57be3d5 | ||
|
|
0d0cec6b66 | ||
|
|
7ba62f9838 | ||
|
|
e80395bacf |
3
.github/ISSUE_TEMPLATE/release.md
vendored
3
.github/ISSUE_TEMPLATE/release.md
vendored
@@ -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.
|
||||
|
||||
2
.github/workflows/renovate.yaml
vendored
2
.github/workflows/renovate.yaml
vendored
@@ -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 }}'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
101
applicationset/services/scm_provider/mocks/AzureDevOpsClientFactory.go
generated
Normal file
101
applicationset/services/scm_provider/mocks/AzureDevOpsClientFactory.go
generated
Normal 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
|
||||
}
|
||||
@@ -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
5
assets/swagger.json
generated
@@ -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"
|
||||
|
||||
@@ -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{},
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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'")
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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{
|
||||
|
||||
34
controller/cache/cache_test.go
vendored
34
controller/cache/cache_test.go
vendored
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
BIN
docs/assets/application-view-extension.png
Normal file
BIN
docs/assets/application-view-extension.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 228 KiB |
@@ -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:
|
||||

|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 |
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -456,7 +456,7 @@
|
||||
<div class="header-wrap">
|
||||
<h1 class="project__header__title">Snyk test report</h1>
|
||||
|
||||
<p class="timestamp">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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
1
docs/user-guide/commands/argocd_repo_add.md
generated
1
docs/user-guide/commands/argocd_repo_add.md
generated
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
1041
gitops-engine/pkg/cache/mocks/ClusterCache.go
generated
vendored
1041
gitops-engine/pkg/cache/mocks/ClusterCache.go
generated
vendored
File diff suppressed because it is too large
Load Diff
@@ -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),
|
||||
|
||||
127
gitops-engine/pkg/diff/mocks/ServerSideDryRunner.go
generated
127
gitops-engine/pkg/diff/mocks/ServerSideDryRunner.go
generated
@@ -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
6
go.mod
@@ -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
12
go.sum
@@ -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=
|
||||
|
||||
1300
pkg/apis/application/v1alpha1/generated.pb.go
generated
1300
pkg/apis/application/v1alpha1/generated.pb.go
generated
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
39
resource_customizations/keda.sh/ScaledJob/health.lua
Normal file
39
resource_customizations/keda.sh/ScaledJob/health.lua
Normal 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
|
||||
21
resource_customizations/keda.sh/ScaledJob/health_test.yaml
Normal file
21
resource_customizations/keda.sh/ScaledJob/health_test.yaml
Normal 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
|
||||
57
resource_customizations/keda.sh/ScaledJob/testdata/keda-degraded.yaml
vendored
Normal file
57
resource_customizations/keda.sh/ScaledJob/testdata/keda-degraded.yaml
vendored
Normal 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
|
||||
|
||||
57
resource_customizations/keda.sh/ScaledJob/testdata/keda-healthy.yaml
vendored
Normal file
57
resource_customizations/keda.sh/ScaledJob/testdata/keda-healthy.yaml
vendored
Normal 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
|
||||
|
||||
49
resource_customizations/keda.sh/ScaledJob/testdata/keda-progressing.yaml
vendored
Normal file
49
resource_customizations/keda.sh/ScaledJob/testdata/keda-progressing.yaml
vendored
Normal 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
|
||||
|
||||
59
resource_customizations/keda.sh/ScaledJob/testdata/keda-suspended.yaml
vendored
Normal file
59
resource_customizations/keda.sh/ScaledJob/testdata/keda-suspended.yaml
vendored
Normal 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
|
||||
63
resource_customizations/keda.sh/ScaledJob/testdata/keda-unknown.yaml
vendored
Normal file
63
resource_customizations/keda.sh/ScaledJob/testdata/keda-unknown.yaml
vendored
Normal 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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user