Compare commits

...

1 Commits

Author SHA1 Message Date
morapet
283bab646e sibling of bcc224b32c 2024-10-07 17:19:30 +00:00
113 changed files with 4184 additions and 1515 deletions

View File

@@ -31,7 +31,7 @@ jobs:
docs: ${{ steps.filter.outputs.docs_any_changed }}
steps:
- uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c # v45.0.2
- uses: tj-actions/changed-files@e9772d140489982e0e3704fea5ee93d536f1e275 # v45.0.1
id: filter
with:
# Any file which is not under docs/, ui/ or is not a markdown file is counted as a backend file

View File

@@ -64,7 +64,7 @@ jobs:
git stash pop
- name: Create pull request
uses: peter-evans/create-pull-request@6cd32fd93684475c31847837f87bb135d40a2b79 # v7.0.3
uses: peter-evans/create-pull-request@d121e62763d8cc35b5fb1710e887d6e69a52d3a4 # v7.0.2
with:
commit-message: "Bump version to ${{ inputs.TARGET_VERSION }}"
title: "Bump version to ${{ inputs.TARGET_VERSION }} on ${{ inputs.TARGET_BRANCH }} branch"

View File

@@ -295,7 +295,7 @@ jobs:
if: ${{ env.UPDATE_VERSION == 'true' }}
- name: Create PR to update VERSION on master branch
uses: peter-evans/create-pull-request@6cd32fd93684475c31847837f87bb135d40a2b79 # v7.0.3
uses: peter-evans/create-pull-request@d121e62763d8cc35b5fb1710e887d6e69a52d3a4 # v7.0.2
with:
commit-message: Bump version in master
title: "chore: Bump version in master"

View File

@@ -3,9 +3,9 @@ header:
expiration-date: '2024-10-31T00:00:00.000Z' # One year from initial release.
last-updated: '2023-10-27'
last-reviewed: '2023-10-27'
commit-hash: 74a367d10e7110209610ba3ec225539ebe5f7522
commit-hash: fe606708859574b9b6102a505e260fac5d3fb14e
project-url: https://github.com/argoproj/argo-cd
project-release: v2.14.0
project-release: v2.13.0
changelog: https://github.com/argoproj/argo-cd/releases
license: https://github.com/argoproj/argo-cd/blob/master/LICENSE
project-lifecycle:

View File

@@ -41,6 +41,7 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Beez Innovation Labs](https://www.beezlabs.com/)
1. [Bedag Informatik AG](https://www.bedag.ch/)
1. [Beleza Na Web](https://www.belezanaweb.com.br/)
1. [Believable Bots](https://believablebots.io)
1. [BigPanda](https://bigpanda.io)
1. [BioBox Analytics](https://biobox.io)
1. [BMW Group](https://www.bmwgroup.com/)

View File

@@ -1 +1 @@
2.14.0
2.13.0-rc3

View File

@@ -168,7 +168,7 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera
if err != nil {
return nil, fmt.Errorf("error fetching Secret Bearer token: %w", err)
}
return pullrequest.NewBitbucketServiceBearerToken(ctx, providerConfig.API, appToken, providerConfig.Project, providerConfig.Repo, g.scmRootCAPath, providerConfig.Insecure, caCerts)
return pullrequest.NewBitbucketServiceBearerToken(ctx, appToken, providerConfig.API, providerConfig.Project, providerConfig.Repo, g.scmRootCAPath, providerConfig.Insecure, caCerts)
} else if providerConfig.BasicAuth != nil {
password, err := utils.GetSecretRef(ctx, g.client, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace)
if err != nil {

2
assets/swagger.json generated
View File

@@ -6084,7 +6084,7 @@
"properties": {
"defaultServiceAccount": {
"type": "string",
"title": "ServiceAccountName to be used for impersonation during the sync operation"
"title": "DefaultServiceAccount to be used for impersonation during the sync operation"
},
"namespace": {
"description": "Namespace specifies the target namespace for the application's resources.",

View File

@@ -163,6 +163,7 @@ func NewCommand() *cobra.Command {
}()
go ctrl.Run(ctx, processorsCount)
<-ctx.Done()
return nil
},
}

View File

@@ -48,6 +48,7 @@ type forwardCacheClient struct {
err error
redisHaProxyName string
redisName string
redisPassword string
}
func (c *forwardCacheClient) doLazy(action func(client cache.CacheClient) error) error {
@@ -64,7 +65,7 @@ func (c *forwardCacheClient) doLazy(action func(client cache.CacheClient) error)
return
}
redisClient := redis.NewClient(&redis.Options{Addr: fmt.Sprintf("localhost:%d", redisPort)})
redisClient := redis.NewClient(&redis.Options{Addr: fmt.Sprintf("localhost:%d", redisPort), Password: c.redisPassword})
c.client = cache.NewRedisCache(redisClient, time.Hour, c.compression)
})
if c.err != nil {
@@ -251,12 +252,12 @@ func MaybeStartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOpti
if err != nil {
return fmt.Errorf("error running miniredis: %w", err)
}
appstateCache := appstatecache.NewCache(cache.NewCache(&forwardCacheClient{namespace: namespace, context: ctxStr, compression: compression, redisHaProxyName: clientOpts.RedisHaProxyName, redisName: clientOpts.RedisName}), time.Hour)
redisOptions := &redis.Options{Addr: mr.Addr()}
if err = common.SetOptionalRedisPasswordFromKubeConfig(ctx, kubeClientset, namespace, redisOptions); err != nil {
log.Warnf("Failed to fetch & set redis password for namespace %s: %v", namespace, err)
}
appstateCache := appstatecache.NewCache(cache.NewCache(&forwardCacheClient{namespace: namespace, context: ctxStr, compression: compression, redisHaProxyName: clientOpts.RedisHaProxyName, redisName: clientOpts.RedisName, redisPassword: redisOptions.Password}), time.Hour)
srv := server.NewServer(ctx, server.ArgoCDServerOpts{
EnableGZip: false,
Namespace: namespace,

View File

@@ -48,6 +48,8 @@ func AddProjFlags(command *cobra.Command, opts *ProjectOpts) {
command.Flags().StringArrayVar(&opts.allowedNamespacedResources, "allow-namespaced-resource", []string{}, "List of allowed namespaced resources")
command.Flags().StringArrayVar(&opts.deniedNamespacedResources, "deny-namespaced-resource", []string{}, "List of denied namespaced resources")
command.Flags().StringSliceVar(&opts.SourceNamespaces, "source-namespaces", []string{}, "List of source namespaces for applications")
command.Flags().StringArrayVar(&opts.destinationServiceAccounts, "dest-service-accounts", []string{},
"Destination server, namespace and target service account (e.g. https://192.168.99.100:8443,default,default-sa)")
}
func getGroupKindList(values []string) []v1.GroupKind {
@@ -98,8 +100,8 @@ func (opts *ProjectOpts) GetDestinationServiceAccounts() []v1alpha1.ApplicationD
destinationServiceAccounts := make([]v1alpha1.ApplicationDestinationServiceAccount, 0)
for _, destStr := range opts.destinationServiceAccounts {
parts := strings.Split(destStr, ",")
if len(parts) != 2 {
log.Fatalf("Expected destination of the form: server,namespace. Received: %s", destStr)
if len(parts) != 3 {
log.Fatalf("Expected destination service account of the form: server,namespace, defaultServiceAccount. Received: %s", destStr)
} else {
destinationServiceAccounts = append(destinationServiceAccounts, v1alpha1.ApplicationDestinationServiceAccount{
Server: parts[0],

View File

@@ -5,6 +5,8 @@ import (
"github.com/stretchr/testify/assert"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
func TestProjectOpts_ResourceLists(t *testing.T) {
@@ -22,3 +24,27 @@ func TestProjectOpts_ResourceLists(t *testing.T) {
[]v1.GroupKind{{Group: "rbac.authorization.k8s.io", Kind: "ClusterRole"}}, opts.GetDeniedClusterResources(),
)
}
func TestProjectOpts_GetDestinationServiceAccounts(t *testing.T) {
opts := ProjectOpts{
destinationServiceAccounts: []string{
"https://192.168.99.100:8443,test-ns,test-sa",
"https://kubernetes.default.svc.local:6443,guestbook,guestbook-sa",
},
}
assert.ElementsMatch(t,
[]v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://192.168.99.100:8443",
Namespace: "test-ns",
DefaultServiceAccount: "test-sa",
},
{
Server: "https://kubernetes.default.svc.local:6443",
Namespace: "guestbook",
DefaultServiceAccount: "guestbook-sa",
},
}, opts.GetDestinationServiceAccounts(),
)
}

View File

@@ -64,6 +64,7 @@ type fakeData struct {
metricsCacheExpiration time.Duration
applicationNamespaces []string
updateRevisionForPathsResponse *apiclient.UpdateRevisionForPathsResponse
additionalObjs []runtime.Object
}
type MockKubectl struct {
@@ -133,7 +134,9 @@ func newFakeController(data *fakeData, repoErr error) *ApplicationController {
},
Data: data.configMapData,
}
kubeClient := fake.NewSimpleClientset(&clust, &cm, &secret)
runtimeObjs := []runtime.Object{&clust, &secret, &cm}
runtimeObjs = append(runtimeObjs, data.additionalObjs...)
kubeClient := fake.NewSimpleClientset(runtimeObjs...)
settingsMgr := settings.NewSettingsManager(context.Background(), kubeClient, test.FakeArgoCDNamespace)
kubectl := &MockKubectl{Kubectl: &kubetest.MockKubectlCmd{}}
ctrl, err := NewApplicationController(

View File

@@ -44,6 +44,10 @@ const (
// EnvVarSyncWaveDelay is an environment variable which controls the delay in seconds between
// each sync-wave
EnvVarSyncWaveDelay = "ARGOCD_SYNC_WAVE_DELAY"
// serviceAccountDisallowedCharSet contains the characters that are not allowed to be present
// in a DefaultServiceAccount configured for a DestinationServiceAccount
serviceAccountDisallowedCharSet = "!*[]{}\\/"
)
func (m *appStateManager) getOpenAPISchema(server string) (openapi.Resources, error) {
@@ -287,8 +291,13 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
}
trackingMethod := argo.GetTrackingMethod(m.settingsMgr)
if m.settingsMgr.IsImpersonationEnabled() {
serviceAccountToImpersonate, err := deriveServiceAccountName(proj, app)
impersonationEnabled, err := m.settingsMgr.IsImpersonationEnabled()
if err != nil {
log.Errorf("could not get impersonation feature flag: %v", err)
return
}
if impersonationEnabled {
serviceAccountToImpersonate, err := deriveServiceAccountToImpersonate(proj, app)
if err != nil {
state.Phase = common.OperationError
state.Message = fmt.Sprintf("failed to find a matching service account to impersonate: %v", err)
@@ -557,9 +566,9 @@ func syncWindowPreventsSync(app *v1alpha1.Application, proj *v1alpha1.AppProject
return !window.CanSync(isManual)
}
// deriveServiceAccountName determines the service account to be used for impersonation for the sync operation.
// deriveServiceAccountToImpersonate determines the service account to be used for impersonation for the sync operation.
// The returned service account will be fully qualified including namespace and the service account name in the format system:serviceaccount:<namespace>:<service_account>
func deriveServiceAccountName(project *v1alpha1.AppProject, application *v1alpha1.Application) (string, error) {
func deriveServiceAccountToImpersonate(project *v1alpha1.AppProject, application *v1alpha1.Application) (string, error) {
// spec.Destination.Namespace is optional. If not specified, use the Application's
// namespace
serviceAccountNamespace := application.Spec.Destination.Namespace
@@ -569,10 +578,18 @@ func deriveServiceAccountName(project *v1alpha1.AppProject, application *v1alpha
// Loop through the destinationServiceAccounts and see if there is any destination that is a candidate.
// if so, return the service account specified for that destination.
for _, item := range project.Spec.DestinationServiceAccounts {
dstServerMatched := glob.Match(item.Server, application.Spec.Destination.Server)
dstNamespaceMatched := glob.Match(item.Namespace, application.Spec.Destination.Namespace)
dstServerMatched, err := glob.MatchWithError(item.Server, application.Spec.Destination.Server)
if err != nil {
return "", fmt.Errorf("invalid glob pattern for destination server: %w", err)
}
dstNamespaceMatched, err := glob.MatchWithError(item.Namespace, application.Spec.Destination.Namespace)
if err != nil {
return "", fmt.Errorf("invalid glob pattern for destination namespace: %w", err)
}
if dstServerMatched && dstNamespaceMatched {
if strings.Contains(item.DefaultServiceAccount, ":") {
if strings.Trim(item.DefaultServiceAccount, " ") == "" || strings.ContainsAny(item.DefaultServiceAccount, serviceAccountDisallowedCharSet) {
return "", fmt.Errorf("default service account contains invalid chars '%s'", item.DefaultServiceAccount)
} else if strings.Contains(item.DefaultServiceAccount, ":") {
// service account is specified along with its namespace.
return fmt.Sprintf("system:serviceaccount:%s", item.DefaultServiceAccount), nil
} else {

View File

@@ -2,6 +2,7 @@ package controller
import (
"context"
"strconv"
"testing"
"github.com/argoproj/gitops-engine/pkg/sync"
@@ -9,6 +10,7 @@ import (
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
@@ -644,6 +646,771 @@ func TestNormalizeTargetResourcesWithList(t *testing.T) {
})
}
func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
type fixture struct {
project *v1alpha1.AppProject
application *v1alpha1.Application
}
setup := func(destinationServiceAccounts []v1alpha1.ApplicationDestinationServiceAccount, destinationNamespace, destinationServerURL, applicationNamespace string) *fixture {
project := &v1alpha1.AppProject{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd-ns",
Name: "testProj",
},
Spec: v1alpha1.AppProjectSpec{
DestinationServiceAccounts: destinationServiceAccounts,
},
}
app := &v1alpha1.Application{
ObjectMeta: v1.ObjectMeta{
Namespace: applicationNamespace,
Name: "testApp",
},
Spec: v1alpha1.ApplicationSpec{
Project: "testProj",
Destination: v1alpha1.ApplicationDestination{
Server: destinationServerURL,
Namespace: destinationNamespace,
},
},
}
return &fixture{
project: project,
application: app,
}
}
t.Run("empty destination service accounts", func(t *testing.T) {
// given an application referring a project with no destination service accounts
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := ""
expectedErrMsg := "no matching service account found for destination server https://kubernetes.svc.local and namespace testns"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
assert.Equal(t, expectedSA, sa)
// then, there should be an error saying no valid match was found
assert.EqualError(t, err, expectedErrMsg)
})
t.Run("exact match of destination namespace", func(t *testing.T) {
// given an application referring a project with exactly one destination service account that matches the application destination,
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should be no error and should use the right service account for impersonation
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("exact one match with multiple destination service accounts", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts having one exact match for application destination
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "guestbook",
DefaultServiceAccount: "guestbook-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "guestbook-test",
DefaultServiceAccount: "guestbook-test-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should be no error and should use the right service account for impersonation
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("first match to be used when multiple matches are available", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts having multiple match for application destination
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa-2",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa-3",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "guestbook",
DefaultServiceAccount: "guestbook-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should be no error and it should use the first matching service account for impersonation
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("first match to be used when glob pattern is used", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts with glob patterns matching the application destination
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "test*",
DefaultServiceAccount: "test-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa-2",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should not be any error and should use the first matching glob pattern service account for impersonation
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("no match among a valid list", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts with no matches for application destination
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "test1",
DefaultServiceAccount: "test-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "test2",
DefaultServiceAccount: "test-sa-2",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := ""
expectedErrMsg := "no matching service account found for destination server https://kubernetes.svc.local and namespace testns"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should be an error saying no match was found
require.EqualError(t, err, expectedErrMsg)
assert.Equal(t, expectedSA, sa)
})
t.Run("app destination namespace is empty", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts with empty application destination namespace
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
DefaultServiceAccount: "test-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "*",
DefaultServiceAccount: "test-sa-2",
},
}
destinationNamespace := ""
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:argocd-ns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should not be any error and the service account configured for with empty namespace should be used.
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("match done via catch all glob pattern", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts having a catch all glob pattern
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "testns1",
DefaultServiceAccount: "test-sa-2",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "*",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should not be any error and the catch all service account should be returned
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("match done via invalid glob pattern", func(t *testing.T) {
// given an application referring a project with a destination service account having an invalid glob pattern for namespace
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "e[[a*",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := ""
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there must be an error as the glob pattern is invalid.
require.ErrorContains(t, err, "invalid glob pattern for destination namespace")
assert.Equal(t, expectedSA, sa)
})
t.Run("sa specified with a namespace", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts having a matching service account specified with its namespace
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "myns:test-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "*",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:myns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
assert.Equal(t, expectedSA, sa)
// then, there should not be any error and the service account with its namespace should be returned.
require.NoError(t, err)
})
}
func TestDeriveServiceAccountMatchingServers(t *testing.T) {
type fixture struct {
project *v1alpha1.AppProject
application *v1alpha1.Application
}
setup := func(destinationServiceAccounts []v1alpha1.ApplicationDestinationServiceAccount, destinationNamespace, destinationServerURL, applicationNamespace string) *fixture {
project := &v1alpha1.AppProject{
ObjectMeta: v1.ObjectMeta{
Namespace: "argocd-ns",
Name: "testProj",
},
Spec: v1alpha1.AppProjectSpec{
DestinationServiceAccounts: destinationServiceAccounts,
},
}
app := &v1alpha1.Application{
ObjectMeta: v1.ObjectMeta{
Namespace: applicationNamespace,
Name: "testApp",
},
Spec: v1alpha1.ApplicationSpec{
Project: "testProj",
Destination: v1alpha1.ApplicationDestination{
Server: destinationServerURL,
Namespace: destinationNamespace,
},
},
}
return &fixture{
project: project,
application: app,
}
}
t.Run("exact one match with multiple destination service accounts", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts and one exact match for application destination
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "guestbook",
DefaultServiceAccount: "guestbook-sa",
},
{
Server: "https://abc.svc.local",
Namespace: "guestbook",
DefaultServiceAccount: "guestbook-test-sa",
},
{
Server: "https://cde.svc.local",
Namespace: "guestbook",
DefaultServiceAccount: "default-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should not be any error and the right service account must be returned.
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("first match to be used when multiple matches are available", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts and multiple matches for application destination
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa-2",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "guestbook",
DefaultServiceAccount: "guestbook-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should not be any error and first matching service account should be used
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("first match to be used when glob pattern is used", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts with a matching glob pattern and exact match
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "test*",
DefaultServiceAccount: "test-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa-2",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
assert.Equal(t, expectedSA, sa)
// then, there should not be any error and the service account of the glob pattern, being the first match should be returned.
require.NoError(t, err)
})
t.Run("no match among a valid list", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts with no match
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa",
},
{
Server: "https://abc.svc.local",
Namespace: "testns",
DefaultServiceAccount: "test-sa-2",
},
{
Server: "https://cde.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://xyz.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := ""
expectedErr := "no matching service account found for destination server https://xyz.svc.local and namespace testns"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there an error with appropriate message must be returned
require.EqualError(t, err, expectedErr)
assert.Equal(t, expectedSA, sa)
})
t.Run("match done via catch all glob pattern", func(t *testing.T) {
// given an application referring a project with multiple destination service accounts with matching catch all glob pattern
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "testns1",
DefaultServiceAccount: "test-sa-2",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
{
Server: "*",
Namespace: "*",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://localhost:6443"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should not be any error and the service account of the glob pattern match must be returned.
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("match done via invalid glob pattern", func(t *testing.T) {
// given an application referring a project with a destination service account having an invalid glob pattern for server
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "e[[a*",
Namespace: "test-ns",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := ""
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there must be an error as the glob pattern is invalid.
require.ErrorContains(t, err, "invalid glob pattern for destination server")
assert.Equal(t, expectedSA, sa)
})
t.Run("sa specified with a namespace", func(t *testing.T) {
// given app sync impersonation feature is enabled and matching service account is prefixed with a namespace
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://abc.svc.local",
Namespace: "testns",
DefaultServiceAccount: "myns:test-sa",
},
{
Server: "https://kubernetes.svc.local",
Namespace: "default",
DefaultServiceAccount: "default-sa",
},
{
Server: "*",
Namespace: "*",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://abc.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:myns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
// then, there should not be any error and the service account with the given namespace prefix must be returned.
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
}
func TestSyncWithImpersonate(t *testing.T) {
type fixture struct {
project *v1alpha1.AppProject
application *v1alpha1.Application
controller *ApplicationController
}
setup := func(impersonationEnabled bool, destinationNamespace, serviceAccountName string) *fixture {
app := newFakeApp()
app.Status.OperationState = nil
app.Status.History = nil
project := &v1alpha1.AppProject{
ObjectMeta: v1.ObjectMeta{
Namespace: test.FakeArgoCDNamespace,
Name: "default",
},
Spec: v1alpha1.AppProjectSpec{
DestinationServiceAccounts: []v1alpha1.
ApplicationDestinationServiceAccount{
{
Server: "https://localhost:6443",
Namespace: destinationNamespace,
DefaultServiceAccount: serviceAccountName,
},
},
},
}
additionalObjs := []runtime.Object{}
if serviceAccountName != "" {
syncServiceAccount := &corev1.ServiceAccount{
ObjectMeta: v1.ObjectMeta{
Name: serviceAccountName,
Namespace: test.FakeDestNamespace,
},
}
additionalObjs = append(additionalObjs, syncServiceAccount)
}
data := fakeData{
apps: []runtime.Object{app, project},
manifestResponse: &apiclient.ManifestResponse{
Manifests: []string{},
Namespace: test.FakeDestNamespace,
Server: "https://localhost:6443",
Revision: "abc123",
},
managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{},
configMapData: map[string]string{
"application.sync.impersonation.enabled": strconv.FormatBool(impersonationEnabled),
},
additionalObjs: additionalObjs,
}
ctrl := newFakeController(&data, nil)
return &fixture{
project: project,
application: app,
controller: ctrl,
}
}
t.Run("sync with impersonation and no matching service account", func(t *testing.T) {
// given app sync impersonation feature is enabled with an application referring a project no matching service account
f := setup(true, test.FakeArgoCDNamespace, "")
opMessage := "failed to find a matching service account to impersonate: no matching service account found for destination server https://localhost:6443 and namespace fake-dest-ns"
opState := &v1alpha1.OperationState{
Operation: v1alpha1.Operation{
Sync: &v1alpha1.SyncOperation{
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: common.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then, app sync should fail with expected error message in operation state
assert.Equal(t, common.OperationError, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
t.Run("sync with impersonation and empty service account match", func(t *testing.T) {
// given app sync impersonation feature is enabled with an application referring a project matching service account that is an empty string
f := setup(true, test.FakeDestNamespace, "")
opMessage := "failed to find a matching service account to impersonate: default service account contains invalid chars ''"
opState := &v1alpha1.OperationState{
Operation: v1alpha1.Operation{
Sync: &v1alpha1.SyncOperation{
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: common.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then app sync should fail with expected error message in operation state
assert.Equal(t, common.OperationError, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
t.Run("sync with impersonation and matching sa", func(t *testing.T) {
// given app sync impersonation feature is enabled with an application referring a project matching service account
f := setup(true, test.FakeDestNamespace, "test-sa")
opMessage := "successfully synced (no more tasks)"
opState := &v1alpha1.OperationState{
Operation: v1alpha1.Operation{
Sync: &v1alpha1.SyncOperation{
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: common.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then app sync should not fail
assert.Equal(t, common.OperationSucceeded, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
t.Run("sync without impersonation", func(t *testing.T) {
// given app sync impersonation feature is disabled with an application referring a project matching service account
f := setup(false, test.FakeDestNamespace, "")
opMessage := "successfully synced (no more tasks)"
opState := &v1alpha1.OperationState{
Operation: v1alpha1.Operation{
Sync: &v1alpha1.SyncOperation{
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: common.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then application sync should pass using the control plane service account
assert.Equal(t, common.OperationSucceeded, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
}
func dig[T any](obj interface{}, path []interface{}) T {
i := obj

View File

@@ -32,23 +32,41 @@ function initializeVersionDropdown() {
window[callbackName] = function(response) {
const div = document.createElement('div');
div.innerHTML = response.html;
document.querySelector(".md-header__inner > .md-header__title").appendChild(div);
const headerTitle = document.querySelector(".md-header__inner > .md-header__title");
if (headerTitle) {
headerTitle.appendChild(div);
}
const container = div.querySelector('.rst-versions');
if (!container) return; // Exit if container not found
// Add caret icon
var caret = document.createElement('div');
caret.innerHTML = "<i class='fa fa-caret-down dropdown-caret'></i>";
caret.classList.add('dropdown-caret');
div.querySelector('.rst-current-version').appendChild(caret);
const currentVersionElem = div.querySelector('.rst-current-version');
if (currentVersionElem) {
currentVersionElem.appendChild(caret);
}
div.querySelector('.rst-current-version').addEventListener('click', function() {
container.classList.toggle('shift-up');
});
// Add click listener to toggle dropdown
if (currentVersionElem && container) {
currentVersionElem.addEventListener('click', function() {
container.classList.toggle('shift-up');
});
}
// Sorting Logic
sortVersionLinks(container);
};
// Load CSS
var CSSLink = document.createElement('link');
CSSLink.rel = 'stylesheet';
CSSLink.href = '/assets/versions.css';
document.getElementsByTagName('head')[0].appendChild(CSSLink);
// Load JSONP Script
var script = document.createElement('script');
const currentVersion = getCurrentVersion();
script.src = 'https://argo-cd.readthedocs.io/_/api/v2/footer_html/?' +
@@ -56,6 +74,58 @@ function initializeVersionDropdown() {
document.getElementsByTagName('head')[0].appendChild(script);
}
// Function to sort version links
function sortVersionLinks(container) {
// Find all <dl> elements within the container
const dlElements = container.querySelectorAll('dl');
dlElements.forEach(dl => {
const dt = dl.querySelector('dt');
if (dt && dt.textContent.trim().toLowerCase() === 'versions') {
// Found the Versions <dl>
const ddElements = Array.from(dl.querySelectorAll('dd'));
// Define sorting criteria
ddElements.sort((a, b) => {
const aText = a.textContent.trim().toLowerCase();
const bText = b.textContent.trim().toLowerCase();
// Prioritize 'latest' and 'stable'
if (aText === 'latest') return -1;
if (bText === 'latest') return 1;
if (aText === 'stable') return -1;
if (bText === 'stable') return 1;
// Extract version numbers (e.g., release-2.9)
const aVersionMatch = aText.match(/release-(\d+(\.\d+)*)/);
const bVersionMatch = bText.match(/release-(\d+(\.\d+)*)/);
if (aVersionMatch && bVersionMatch) {
const aVersion = aVersionMatch[1].split('.').map(Number);
const bVersion = bVersionMatch[1].split('.').map(Number);
for (let i = 0; i < Math.max(aVersion.length, bVersion.length); i++) {
const aNum = aVersion[i] || 0;
const bNum = bVersion[i] || 0;
if (aNum > bNum) return -1;
if (aNum < bNum) return 1;
}
return 0;
}
// Fallback to alphabetical order
return aText.localeCompare(bText);
});
// Remove existing <dd> elements
ddElements.forEach(dd => dl.removeChild(dd));
// Append sorted <dd> elements
ddElements.forEach(dd => dl.appendChild(dd));
}
});
}
// VERSION WARNINGS
window.addEventListener("DOMContentLoaded", function() {
var margin = 30;

View File

@@ -1,7 +1,7 @@
# Application Sync using impersonation
!!! warning "Alpha Feature"
This is an experimental, alpha-quality feature that allows you to control the service account used for the sync operation. The configured service account, could have lesser privileges required for creating resources compared to the highly privileged access required for the control plane operations.
This is an experimental, alpha-quality feature that allows you to control the service account used for the sync operation. The configured service account could have lesser privileges required for creating resources compared to the highly privileged access required for the control plane operations.
!!! warning
Please read this documentation carefully before you enable this feature. Misconfiguration could lead to potential security issues.
@@ -94,7 +94,7 @@ spec:
sourceRepos:
- '*'
destinations:
- *
- '*'
destinationServiceAccounts:
- server: https://kubernetes.default.svc
namespace: guestbook

View File

@@ -329,14 +329,14 @@ data:
# spread out the refreshes and give time to the repo-server to catch up. The jitter is the maximum duration that can be
# added to the sync timeout. So, if the sync timeout is 3 minutes and the jitter is 1 minute, then the actual timeout will
# be between 3 and 4 minutes. Disabled when the value is 0, defaults to 0.
timeout.reconciliation.jitter: 0
timeout.reconciliation.jitter: "0"
# cluster.inClusterEnabled indicates whether to allow in-cluster server address. This is enabled by default.
cluster.inClusterEnabled: "true"
# The maximum number of pod logs to render in UI. If the application has more than this number of pods, the logs will not be rendered.
# This is to prevent the UI from becoming unresponsive when rendering a large number of logs. Default is 10.
server.maxPodLogsToRender: 10
server.maxPodLogsToRender: "10"
# Application pod logs RBAC enforcement enables control over who can and who can't view application pod logs.
# When you enable the switch, pod logs will be visible only to admin role by default. Other roles/users will not be able to view them via cli and UI.
@@ -425,7 +425,7 @@ data:
name: some-cluster
server: https://some-cluster
# The maximum size of the payload that can be sent to the webhook server.
webhook.maxPayloadSizeMB: 1024
webhook.maxPayloadSizeMB: "1024"
# application.sync.impersonation.enabled indicates whether the application sync can be decoupled from control plane service account using impersonation.
# application.sync.impersonation.enabled enables application sync to use a custom service account, via impersonation. This allows decoupling sync from control-plane service account.
application.sync.impersonation.enabled: "false"

View File

@@ -98,20 +98,27 @@ data:
return hs
```
In order to prevent duplication of the custom health check for potentially multiple resources, it is also possible to specify a wildcard in the resource kind, and anywhere in the resource group, like this:
In order to prevent duplication of custom health checks for potentially multiple resources, it is also possible to
specify a wildcard in the resource kind, and anywhere in the resource group, like this:
```yaml
resource.customizations.health.ec2.aws.crossplane.io_*: |
...
resource.customizations: |
ec2.aws.crossplane.io/*:
health.lua: |
...
```
```yaml
resource.customizations.health.*.aws.crossplane.io_*: |
...
# If a key _begins_ with a wildcard, please ensure that the GVK key is quoted.
resource.customizations: |
"*.aws.crossplane.io/*":
health.lua: |
...
```
!!!important
Please, note that there can be ambiguous resolution of wildcards, see [#16905](https://github.com/argoproj/argo-cd/issues/16905)
Please, note that wildcards are only supported when using the `resource.customizations` key, the `resource.customizations.health.<group>_<kind>`
style keys do not work since wildcards (`*`) are not supported in Kubernetes configmap keys.
The `obj` is a global variable which contains the resource. The script must return an object with status and optional message field.
The custom health check might return one of the following health statuses:
@@ -121,7 +128,7 @@ The custom health check might return one of the following health statuses:
* `Degraded` - the resource is degraded
* `Suspended` - the resource is suspended and waiting for some external event to resume (e.g. suspended CronJob or paused Deployment)
By default health typically returns `Progressing` status.
By default, health typically returns a `Progressing` status.
NOTE: As a security measure, access to the standard Lua libraries will be disabled by default. Admins can control access by
setting `resource.customizations.useOpenLibs.<group>_<kind>`. In the following example, standard libraries are enabled for health check of `cert-manager.io/Certificate`.

View File

@@ -471,7 +471,7 @@ Once we create this service, we can configure the Ingress to conditionally route
```
## [Istio](https://www.istio.io)
You can put Argo CD behind Istio using following configurations. Here we will achieve both serving Argo CD behind istio and using subpath on Istio
You can put Argo CD behind Istio using following configurations. Here we will achive both serving Argo CD behind istio and using subpath on Istio
First we need to make sure that we can run Argo CD with subpath (ie /argocd). For this we have used install.yaml from argocd project as is

View File

@@ -40,27 +40,6 @@ You need to check your argocd-notifications controller version. For instance, th
You have not defined `xxxx` in `argocd-notifications-cm` or to fail to parse settings.
### GitHub.repoURL (\u003cno value\u003e) does not have a / using the configuration
You probably have an Application with [multiple sources](https://argo-cd.readthedocs.io/en/stable/user-guide/multiple_sources/):
```yaml
spec:
sources: # <- multiple sources
- repoURL: https://github.com/exampleOrg/first.git
path: sources/example
- repoURL: https://github.com/exampleOrg/second.git
targetRevision: "{{branch}}"
```
So standard notification template won't work (`{{.app.spec.source.repoURL}}`). You should choose a single source instead:
```yaml
template.example: |
github:
repoURLPath: "{{ (index .app.spec.sources 0).repoURL }}"
```
## config referenced xxx, but key does not exist in secret
- If you are using a custom secret, check that the secret is in the same namespace

View File

@@ -1,2 +1,5 @@
This page is populated for released Argo CD versions. Use the version selector to view this table for a specific
version.
| Argo CD version | Kubernetes versions |
|-----------------|---------------------|
| 2.13 | |
| 2.12 | |
| 2.11 | v1.29, v1.28, v1.27, v1.26, v1.25 |

View File

@@ -1,5 +1,9 @@
# v2.12 to 2.13
## Upgraded Helm Version
Note that bundled Helm version has been upgraded from 3.15.2 to 3.15.4.
## Custom Resource Actions for Flux Resources
[`Custom Resource Actions`](../resource_actions.md#Custom-Resource-Actions) have been added for Flux Resources.
@@ -66,4 +70,4 @@ The default extension for log files generated by Argo CD when using the "Downloa
If you have any custom scripts or tools that depend on the `.txt` extension, please update them accordingly.
## Added proxy to kustomize
Proxy config set on repository credentials / repository templates is now passed down to the `kustomize build` command.
Proxy config set on repository credentials / repository templates is now passed down to the `kustomie build` command.

View File

@@ -68,9 +68,9 @@ This proposal would allow ArgoCD administrators to manage the cluster permission
### Goals
- Applications may only impersonate ServiceAccounts that live in the same namespace as the destination namespace configured in the application.If the service account is created in a different namespace, then the user can provide the service account name in the format `<namespace>:<service_account_name>` . ServiceAccount to be used for syncing each application is determined by the target destination configured in the `AppProject` associated with the `Application`.
- If impersonation feature is enabled, and no service account name is provided in the associated `AppProject`, then the sync operation would fail with an appropriate error message. Users can configure a catch all service account matching all destinations to avoid such sync errors.
- If impersonation feature is enabled, and no service account name is provided in the associated `AppProject`, then the default service account of the destination namespace of the `Application` should be used.
- Access restrictions implemented through properties in AppProject (if done) must have the existing behavior. From a security standpoint, any restrictions that were available before switching to a service account based approach should continue to exist even when the impersonation feature is enabled.
- The feature can be enabled/disabled only at the system level. Once enabled/disabled, it is applicable to all ArgoCD `Applications`.
- The feature can be enabled/disabled only at the system level. Once enabled/disabled, it is applicable to all Argo CD `Applications`.
### Non-Goals
@@ -82,7 +82,7 @@ As part of this proposal, it would be possible for an ArgoCD Admin to specify a
When applications gets synced, based on its destination (target cluster and namespace combination), the `defaultServiceAccount` configured in the `AppProject` will be selected and used for impersonation when executing the kubectl commands for the sync operation.
We would be introducing a new element `destinationServiceAccounts` in `AppProject.spec`. This element is used for the sole purpose of specifying the impersonation configuration. The `defaultServiceAccount` configured for the `AppProject` would be used for the sync operation for a particular destination cluster and namespace. If impersonation feature is enabled and no specific service account is provided in the `AppProject` CR, then the sync operation will fail with an error. Users can configure a catch all service account matching all destinations to avoid such sync errors.
We would be introducing a new element `destinationServiceAccounts` in `AppProject.spec`. This element is used for the sole purpose of specifying the impersonation configuration. The `defaultServiceAccount` configured for the `AppProject` would be used for the sync operation for a particular destination cluster and namespace. If impersonation feature is enabled and no specific service account is provided in the `AppProject` CR, then the `default` service account in the destination namespace would be used for impersonation.
```yaml
apiVersion: argoproj.io/v1alpha1
@@ -109,7 +109,7 @@ spec:
- server: https://kubernetes.default.svc
namespace: guestbook-stage
defaultServiceAccount: guestbook-stage-deployer
- server: '*
- server: '*'
namespace: '*'
defaultServiceAccount: default # catch all service account to be used when all other matches fail.
```
@@ -161,7 +161,10 @@ So that, I can use a generic convention of naming service accounts and avoid ass
#### Component: ArgoCD Application Controller
- Provide a configuration in `argocd-cm` which can be modified to enable the Impersonation feature. Set `application.sync.impersonation.enabled: "true"` in the Argo CD ConfigMap. Default value of `application.sync.impersonation.enabled` would be `"false"` and user has to explicitly override it to use this feature.
- Provide a configuration in `argocd-cm` which can be modified to enable the Impersonation feature. Set `applicationcontroller.enable.impersonation: true` in the Argo CD ConfigMap. Default value of `applicationcontroller.enable.impersonation` would be `false` and user has to explicitly override it to use this feature.
- Provide an option to override the Impersonation feature using environment variables.
Set `ARGOCD_APPLICATION_CONTROLLER_ENABLE_IMPERSONATION=true` in the Application controller environment variables. Default value of the environment variable must be `false` and user has to explicitly set it to `true` to use this feature.
- Provide an option to enable this feature using a command line flag `--enable-impersonation`. This new argument option needs to be added to the Application controller args.
- Fix Application Controller `sync.go` to set the Impersonate configuration from the AppProject CR to the `SyncContext` Object (rawConfig and restConfig field, need to understand which config is used for the actual sync and if both configs need to be impersonated.)
#### Component: ArgoCD UI

View File

@@ -14,11 +14,11 @@ recent minor releases.
| | Critical | High | Medium | Low |
|---:|:--------:|:----:|:------:|:---:|
| [go.mod](master/argocd-test.html) | 0 | 0 | 1 | 0 |
| [ui/yarn.lock](master/argocd-test.html) | 0 | 0 | 2 | 0 |
| [ui/yarn.lock](master/argocd-test.html) | 0 | 0 | 1 | 0 |
| [dex:v2.41.1](master/ghcr.io_dexidp_dex_v2.41.1.html) | 0 | 0 | 0 | 1 |
| [haproxy:2.6.17-alpine](master/public.ecr.aws_docker_library_haproxy_2.6.17-alpine.html) | 0 | 0 | 2 | 3 |
| [redis:7.0.15-alpine](master/public.ecr.aws_docker_library_redis_7.0.15-alpine.html) | 0 | 0 | 0 | 0 |
| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 4 | 8 |
| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 6 | 8 |
| [redis:7.0.15-alpine](master/redis_7.0.15-alpine.html) | 0 | 0 | 0 | 0 |
| [install.yaml](master/argocd-iac-install.html) | - | - | - | - |
| [namespace-install.yaml](master/argocd-iac-namespace-install.html) | - | - | - | - |
@@ -28,37 +28,37 @@ recent minor releases.
| | Critical | High | Medium | Low |
|---:|:--------:|:----:|:------:|:---:|
| [go.mod](v2.12.3/argocd-test.html) | 0 | 0 | 2 | 0 |
| [ui/yarn.lock](v2.12.3/argocd-test.html) | 0 | 0 | 2 | 0 |
| [ui/yarn.lock](v2.12.3/argocd-test.html) | 0 | 0 | 1 | 0 |
| [dex:v2.38.0](v2.12.3/ghcr.io_dexidp_dex_v2.38.0.html) | 0 | 0 | 6 | 6 |
| [haproxy:2.6.17-alpine](v2.12.3/public.ecr.aws_docker_library_haproxy_2.6.17-alpine.html) | 0 | 0 | 2 | 3 |
| [redis:7.0.15-alpine](v2.12.3/public.ecr.aws_docker_library_redis_7.0.15-alpine.html) | 0 | 0 | 0 | 0 |
| [argocd:v2.12.3](v2.12.3/quay.io_argoproj_argocd_v2.12.3.html) | 0 | 0 | 8 | 8 |
| [argocd:v2.12.3](v2.12.3/quay.io_argoproj_argocd_v2.12.3.html) | 0 | 0 | 7 | 8 |
| [redis:7.0.15-alpine](v2.12.3/redis_7.0.15-alpine.html) | 0 | 0 | 0 | 0 |
| [install.yaml](v2.12.3/argocd-iac-install.html) | - | - | - | - |
| [namespace-install.yaml](v2.12.3/argocd-iac-namespace-install.html) | - | - | - | - |
### v2.11.8
### v2.11.7
| | Critical | High | Medium | Low |
|---:|:--------:|:----:|:------:|:---:|
| [go.mod](v2.11.8/argocd-test.html) | 0 | 1 | 3 | 0 |
| [ui/yarn.lock](v2.11.8/argocd-test.html) | 0 | 0 | 2 | 0 |
| [dex:v2.38.0](v2.11.8/ghcr.io_dexidp_dex_v2.38.0.html) | 0 | 0 | 6 | 6 |
| [haproxy:2.6.14-alpine](v2.11.8/haproxy_2.6.14-alpine.html) | 0 | 1 | 7 | 6 |
| [argocd:v2.11.8](v2.11.8/quay.io_argoproj_argocd_v2.11.8.html) | 0 | 0 | 7 | 16 |
| [redis:7.0.15-alpine](v2.11.8/redis_7.0.15-alpine.html) | 0 | 0 | 0 | 0 |
| [install.yaml](v2.11.8/argocd-iac-install.html) | - | - | - | - |
| [namespace-install.yaml](v2.11.8/argocd-iac-namespace-install.html) | - | - | - | - |
| [go.mod](v2.11.7/argocd-test.html) | 0 | 1 | 3 | 0 |
| [ui/yarn.lock](v2.11.7/argocd-test.html) | 0 | 0 | 1 | 0 |
| [dex:v2.38.0](v2.11.7/ghcr.io_dexidp_dex_v2.38.0.html) | 0 | 0 | 6 | 6 |
| [haproxy:2.6.14-alpine](v2.11.7/haproxy_2.6.14-alpine.html) | 0 | 1 | 7 | 6 |
| [argocd:v2.11.7](v2.11.7/quay.io_argoproj_argocd_v2.11.7.html) | 0 | 0 | 10 | 20 |
| [redis:7.0.15-alpine](v2.11.7/redis_7.0.15-alpine.html) | 0 | 0 | 0 | 0 |
| [install.yaml](v2.11.7/argocd-iac-install.html) | - | - | - | - |
| [namespace-install.yaml](v2.11.7/argocd-iac-namespace-install.html) | - | - | - | - |
### v2.10.16
| | Critical | High | Medium | Low |
|---:|:--------:|:----:|:------:|:---:|
| [go.mod](v2.10.16/argocd-test.html) | 0 | 1 | 4 | 0 |
| [ui/yarn.lock](v2.10.16/argocd-test.html) | 0 | 0 | 2 | 0 |
| [ui/yarn.lock](v2.10.16/argocd-test.html) | 0 | 0 | 1 | 0 |
| [dex:v2.37.0](v2.10.16/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 1 | 10 | 6 |
| [haproxy:2.6.14-alpine](v2.10.16/haproxy_2.6.14-alpine.html) | 0 | 1 | 7 | 6 |
| [argocd:v2.10.16](v2.10.16/quay.io_argoproj_argocd_v2.10.16.html) | 0 | 0 | 11 | 20 |
| [argocd:v2.10.16](v2.10.16/quay.io_argoproj_argocd_v2.10.16.html) | 0 | 0 | 10 | 20 |
| [redis:7.0.15-alpine](v2.10.16/redis_7.0.15-alpine.html) | 0 | 0 | 0 | 0 |
| [install.yaml](v2.10.16/argocd-iac-install.html) | - | - | - | - |
| [namespace-install.yaml](v2.10.16/argocd-iac-namespace-install.html) | - | - | - | - |

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:20:57 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:20:48 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:21:06 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:20:58 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Snyk test report</title>
<meta name="description" content="3 known vulnerabilities found in 5 vulnerable dependency paths.">
<meta name="description" content="2 known vulnerabilities found in 2 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">
@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:18:53 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:18:34 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -467,8 +467,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>3</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>5 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>2 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2132</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -477,173 +477,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--medium" data-snyk-test="medium">
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
<div class="card__section">
<div class="label label--medium">
<span class="label__text">medium severity</span>
</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:
path-to-regexp
</li>
<li class="card__meta__item">Introduced through:
argo-cd-ui@1.0.0, react-router@4.3.1 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-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.0
</span>
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
argo-cd-ui@1.0.0
<span class="list-paths__item__arrow"></span>
react-router-dom@4.3.1
<span class="list-paths__item__arrow"></span>
react-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.0
</span>
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
argo-cd-ui@1.0.0
<span class="list-paths__item__arrow"></span>
argo-ui@1.0.0
<span class="list-paths__item__arrow"></span>
react-router-dom@4.3.1
<span class="list-paths__item__arrow"></span>
react-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.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 Regular Expression Denial of Service (ReDoS) when including multiple regular expression parameters in a single segment, which will produce the regular expression <code>/^\/([^\/]+?)-([^\/]+?)\/?$/</code>, if two parameters within a single segment are separated by a character other than a <code>/</code> or <code>.</code>. Poor performance will block the event loop and can lead to a DoS.</p>
<p><strong>Note:</strong>
Version 0.1.10 is patched to mitigate this but is also vulnerable if custom regular expressions are used. Due to the existence of this attack vector, the Snyk security team have decided to err on the side of caution in considering the very widely-used v0 branch vulnerable, while the 8.0.0 release has completely eliminated the vulnerable functionality.</p>
<h2 id="workaround">Workaround</h2>
<p>This vulnerability can be avoided by using a custom regular expression for parameters after the first in a segment, which excludes <code>-</code> and <code>/</code>.</p>
<h2 id="poc">PoC</h2>
<pre><code class="language-js">/a${&#39;-a&#39;.repeat(8_000)}/a
</code></pre>
<h2 id="details">Details</h2>
<p>Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.</p>
<p>The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren&#39;t very intuitive and can ultimately end up making it easy for attackers to take your site down.</p>
<p>Lets take the following regular expression as an example:</p>
<pre><code class="language-js">regex = /A(B|C+)+D/
</code></pre>
<p>This regular expression accomplishes the following:</p>
<ul>
<li><code>A</code> The string must start with the letter &#39;A&#39;</li>
<li><code>(B|C+)+</code> The string must then follow the letter A with either the letter &#39;B&#39; or some number of occurrences of the letter &#39;C&#39; (the <code>+</code> matches one or more times). The <code>+</code> at the end of this section states that we can look for one or more matches of this section.</li>
<li><code>D</code> Finally, we ensure this section of the string ends with a &#39;D&#39;</li>
</ul>
<p>The expression would match inputs such as <code>ABBD</code>, <code>ABCCCCD</code>, <code>ABCBCCCD</code> and <code>ACCCCCD</code></p>
<p>It most cases, it doesn&#39;t take very long for a regex engine to find a match:</p>
<pre><code class="language-bash">$ time node -e &#39;/A(B|C+)+D/.test(&quot;ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD&quot;)&#39;
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e &#39;/A(B|C+)+D/.test(&quot;ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX&quot;)&#39;
1.79s user 0.02s system 99% cpu 1.812 total
</code></pre>
<p>The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.</p>
<p>Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesnt match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as <em>catastrophic backtracking</em>.</p>
<p>Let&#39;s look at how our expression runs into this problem, using a shorter string: &quot;ACCCX&quot;. While it seems fairly straightforward, there are still four different ways that the engine could match those three C&#39;s:</p>
<ol>
<li>CCC</li>
<li>CC+C</li>
<li>C+CC</li>
<li>C+C+C.</li>
</ol>
<p>The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use <a href="https://regex101.com/debugger">RegEx 101 debugger</a> to see the engine has to take a total of 38 steps before it can determine the string doesn&#39;t match.</p>
<p>From there, the number of steps the engine must use to validate a string just continues to grow.</p>
<table>
<thead>
<tr>
<th>String</th>
<th align="right">Number of C&#39;s</th>
<th align="right">Number of steps</th>
</tr>
</thead>
<tbody><tr>
<td>ACCCX</td>
<td align="right">3</td>
<td align="right">38</td>
</tr>
<tr>
<td>ACCCCX</td>
<td align="right">4</td>
<td align="right">71</td>
</tr>
<tr>
<td>ACCCCCX</td>
<td align="right">5</td>
<td align="right">136</td>
</tr>
<tr>
<td>ACCCCCCCCCCCCCCX</td>
<td align="right">14</td>
<td align="right">65,553</td>
</tr>
</tbody></table>
<p>By the time the string includes 14 C&#39;s, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.</p>
<h2 id="remediation">Remediation</h2>
<p>Upgrade <code>path-to-regexp</code> to version 8.0.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/pillarjs/path-to-regexp/commit/29b96b4a1de52824e1ca0f49a701183cc4ed476f">GitHub Commit</a></li>
<li><a href="https://github.com/pillarjs/path-to-regexp/commit/60f2121e9b66b7b622cc01080df0aabda9eedee6">GitHub Commit</a></li>
<li><a href="https://blakeembrey.com/posts/2024-09-web-redos/">Vulnerability Write-up</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-JS-PATHTOREGEXP-7925106">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">Concurrent Execution using Shared Resource with Improper Synchronization (&#x27;Race Condition&#x27;)</h2>
<div class="card__section">

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:19:03 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:18:44 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:19:08 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:18:52 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:19:12 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:18:59 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Snyk test report</title>
<meta name="description" content="12 known vulnerabilities found in 66 vulnerable dependency paths.">
<meta name="description" content="14 known vulnerabilities found in 68 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">
@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:19:30 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:19:18 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -470,8 +470,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>12</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>66 vulnerable dependency paths</span></div>
<div class="meta-count"><span>14</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>68 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2355</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -1050,7 +1050,7 @@
</div><!-- .card -->
<div class="card card--vuln disclosure--not-new severity--medium" data-snyk-test="medium">
<h2 class="card__title">CVE-2024-8096</h2>
<h2 class="card__title">Integer Overflow or Wraparound</h2>
<div class="card__section">
<div class="label label--medium">
@@ -1069,7 +1069,7 @@
<li class="card__meta__item">
Vulnerable module:
curl/libcurl3t64-gnutls
expat/libexpat1
</li>
<li class="card__meta__item">Introduced through:
@@ -1091,7 +1091,7 @@
<span class="list-paths__item__arrow"></span>
git@1:2.43.0-1ubuntu7.1
<span class="list-paths__item__arrow"></span>
curl/libcurl3t64-gnutls@8.5.0-2ubuntu10.3
expat/libexpat1@2.6.1-2build1
</span>
@@ -1103,23 +1103,168 @@
<hr/>
<!-- Overview -->
<h2 id="nvd-description">NVD Description</h2>
<p><strong><em>Note:</em></strong> <em>Versions mentioned in the description apply only to the upstream <code>curl</code> package and not the <code>curl</code> package as distributed by <code>Ubuntu</code>.</em>
<p><strong><em>Note:</em></strong> <em>Versions mentioned in the description apply only to the upstream <code>expat</code> package and not the <code>expat</code> package as distributed by <code>Ubuntu</code>.</em>
<em>See <code>How to fix?</code> for <code>Ubuntu:24.04</code> relevant fixed versions and status.</em></p>
<p>When curl is told to use the Certificate Status Request TLS extension, often referred to as OCSP stapling, to verify that the server certificate is valid, it might fail to detect some OCSP problems and instead wrongly consider the response as fine. If the returned status reports another error than &#39;revoked&#39; (like for example &#39;unauthorized&#39;) it is not treated as a bad certficate.</p>
<p>An issue was discovered in libexpat before 2.6.3. dtdCopy in xmlparse.c can have an integer overflow for nDefaultAtts on 32-bit platforms (where UINT_MAX equals SIZE_MAX).</p>
<h2 id="remediation">Remediation</h2>
<p>There is no fixed version for <code>Ubuntu:24.04</code> <code>curl</code>.</p>
<p>There is no fixed version for <code>Ubuntu:24.04</code> <code>expat</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-8096">http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-8096</a></li>
<li><a href="https://curl.se/docs/CVE-2024-8096.html">https://curl.se/docs/CVE-2024-8096.html</a></li>
<li><a href="https://curl.se/docs/CVE-2024-8096.json">https://curl.se/docs/CVE-2024-8096.json</a></li>
<li><a href="https://hackerone.com/reports/2669852">https://hackerone.com/reports/2669852</a></li>
<li><a href="http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45491">http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45491</a></li>
<li><a href="https://github.com/libexpat/libexpat/issues/888">https://github.com/libexpat/libexpat/issues/888</a></li>
<li><a href="https://github.com/libexpat/libexpat/pull/891">https://github.com/libexpat/libexpat/pull/891</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-UBUNTU2404-CURL-7931919">More about this vulnerability</a></p>
<p><a href="https://snyk.io/vuln/SNYK-UBUNTU2404-EXPAT-7885392">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">XML External Entity (XXE) Injection</h2>
<div class="card__section">
<div class="label label--medium">
<span class="label__text">medium severity</span>
</div>
<hr/>
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:24.04
</li>
<li class="card__meta__item">
Vulnerable module:
expat/libexpat1
</li>
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@latest, git@1:2.43.0-1ubuntu7.1 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>:
docker-image|quay.io/argoproj/argocd@latest
<span class="list-paths__item__arrow"></span>
git@1:2.43.0-1ubuntu7.1
<span class="list-paths__item__arrow"></span>
expat/libexpat1@2.6.1-2build1
</span>
</li>
</ul><!-- .list-paths -->
</div><!-- .card__section -->
<hr/>
<!-- Overview -->
<h2 id="nvd-description">NVD Description</h2>
<p><strong><em>Note:</em></strong> <em>Versions mentioned in the description apply only to the upstream <code>expat</code> package and not the <code>expat</code> package as distributed by <code>Ubuntu</code>.</em>
<em>See <code>How to fix?</code> for <code>Ubuntu:24.04</code> relevant fixed versions and status.</em></p>
<p>An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.</p>
<h2 id="remediation">Remediation</h2>
<p>There is no fixed version for <code>Ubuntu:24.04</code> <code>expat</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45490">http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45490</a></li>
<li><a href="https://github.com/libexpat/libexpat/issues/887">https://github.com/libexpat/libexpat/issues/887</a></li>
<li><a href="https://github.com/libexpat/libexpat/pull/890">https://github.com/libexpat/libexpat/pull/890</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-UBUNTU2404-EXPAT-7885502">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">Integer Overflow or Wraparound</h2>
<div class="card__section">
<div class="label label--medium">
<span class="label__text">medium severity</span>
</div>
<hr/>
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:24.04
</li>
<li class="card__meta__item">
Vulnerable module:
expat/libexpat1
</li>
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@latest, git@1:2.43.0-1ubuntu7.1 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>:
docker-image|quay.io/argoproj/argocd@latest
<span class="list-paths__item__arrow"></span>
git@1:2.43.0-1ubuntu7.1
<span class="list-paths__item__arrow"></span>
expat/libexpat1@2.6.1-2build1
</span>
</li>
</ul><!-- .list-paths -->
</div><!-- .card__section -->
<hr/>
<!-- Overview -->
<h2 id="nvd-description">NVD Description</h2>
<p><strong><em>Note:</em></strong> <em>Versions mentioned in the description apply only to the upstream <code>expat</code> package and not the <code>expat</code> package as distributed by <code>Ubuntu</code>.</em>
<em>See <code>How to fix?</code> for <code>Ubuntu:24.04</code> relevant fixed versions and status.</em></p>
<p>An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).</p>
<h2 id="remediation">Remediation</h2>
<p>There is no fixed version for <code>Ubuntu:24.04</code> <code>expat</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45492">http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45492</a></li>
<li><a href="https://github.com/libexpat/libexpat/issues/889">https://github.com/libexpat/libexpat/issues/889</a></li>
<li><a href="https://github.com/libexpat/libexpat/pull/892">https://github.com/libexpat/libexpat/pull/892</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-UBUNTU2404-EXPAT-7885595">More about this vulnerability</a></p>
</div>
</div><!-- .card -->

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:19:34 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:19:22 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:27:49 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:28:10 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:27:58 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:28:21 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Snyk test report</title>
<meta name="description" content="7 known vulnerabilities found in 163 vulnerable dependency paths.">
<meta name="description" content="6 known vulnerabilities found in 160 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">
@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:25:54 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:26:11 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -467,8 +467,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>7</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>163 vulnerable dependency paths</span></div>
<div class="meta-count"><span>6</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>160 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2042</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -3139,173 +3139,6 @@
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXNETHTTP2-6531285">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">Regular Expression Denial of Service (ReDoS)</h2>
<div class="card__section">
<div class="label label--medium">
<span class="label__text">medium severity</span>
</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:
path-to-regexp
</li>
<li class="card__meta__item">Introduced through:
argo-cd-ui@1.0.0, react-router@4.3.1 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-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.0
</span>
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
argo-cd-ui@1.0.0
<span class="list-paths__item__arrow"></span>
react-router-dom@4.3.1
<span class="list-paths__item__arrow"></span>
react-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.0
</span>
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
argo-cd-ui@1.0.0
<span class="list-paths__item__arrow"></span>
argo-ui@1.0.0
<span class="list-paths__item__arrow"></span>
react-router-dom@4.3.1
<span class="list-paths__item__arrow"></span>
react-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.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 Regular Expression Denial of Service (ReDoS) when including multiple regular expression parameters in a single segment, which will produce the regular expression <code>/^\/([^\/]+?)-([^\/]+?)\/?$/</code>, if two parameters within a single segment are separated by a character other than a <code>/</code> or <code>.</code>. Poor performance will block the event loop and can lead to a DoS.</p>
<p><strong>Note:</strong>
Version 0.1.10 is patched to mitigate this but is also vulnerable if custom regular expressions are used. Due to the existence of this attack vector, the Snyk security team have decided to err on the side of caution in considering the very widely-used v0 branch vulnerable, while the 8.0.0 release has completely eliminated the vulnerable functionality.</p>
<h2 id="workaround">Workaround</h2>
<p>This vulnerability can be avoided by using a custom regular expression for parameters after the first in a segment, which excludes <code>-</code> and <code>/</code>.</p>
<h2 id="poc">PoC</h2>
<pre><code class="language-js">/a${&#39;-a&#39;.repeat(8_000)}/a
</code></pre>
<h2 id="details">Details</h2>
<p>Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.</p>
<p>The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren&#39;t very intuitive and can ultimately end up making it easy for attackers to take your site down.</p>
<p>Lets take the following regular expression as an example:</p>
<pre><code class="language-js">regex = /A(B|C+)+D/
</code></pre>
<p>This regular expression accomplishes the following:</p>
<ul>
<li><code>A</code> The string must start with the letter &#39;A&#39;</li>
<li><code>(B|C+)+</code> The string must then follow the letter A with either the letter &#39;B&#39; or some number of occurrences of the letter &#39;C&#39; (the <code>+</code> matches one or more times). The <code>+</code> at the end of this section states that we can look for one or more matches of this section.</li>
<li><code>D</code> Finally, we ensure this section of the string ends with a &#39;D&#39;</li>
</ul>
<p>The expression would match inputs such as <code>ABBD</code>, <code>ABCCCCD</code>, <code>ABCBCCCD</code> and <code>ACCCCCD</code></p>
<p>It most cases, it doesn&#39;t take very long for a regex engine to find a match:</p>
<pre><code class="language-bash">$ time node -e &#39;/A(B|C+)+D/.test(&quot;ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD&quot;)&#39;
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e &#39;/A(B|C+)+D/.test(&quot;ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX&quot;)&#39;
1.79s user 0.02s system 99% cpu 1.812 total
</code></pre>
<p>The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.</p>
<p>Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesnt match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as <em>catastrophic backtracking</em>.</p>
<p>Let&#39;s look at how our expression runs into this problem, using a shorter string: &quot;ACCCX&quot;. While it seems fairly straightforward, there are still four different ways that the engine could match those three C&#39;s:</p>
<ol>
<li>CCC</li>
<li>CC+C</li>
<li>C+CC</li>
<li>C+C+C.</li>
</ol>
<p>The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use <a href="https://regex101.com/debugger">RegEx 101 debugger</a> to see the engine has to take a total of 38 steps before it can determine the string doesn&#39;t match.</p>
<p>From there, the number of steps the engine must use to validate a string just continues to grow.</p>
<table>
<thead>
<tr>
<th>String</th>
<th align="right">Number of C&#39;s</th>
<th align="right">Number of steps</th>
</tr>
</thead>
<tbody><tr>
<td>ACCCX</td>
<td align="right">3</td>
<td align="right">38</td>
</tr>
<tr>
<td>ACCCCX</td>
<td align="right">4</td>
<td align="right">71</td>
</tr>
<tr>
<td>ACCCCCX</td>
<td align="right">5</td>
<td align="right">136</td>
</tr>
<tr>
<td>ACCCCCCCCCCCCCCX</td>
<td align="right">14</td>
<td align="right">65,553</td>
</tr>
</tbody></table>
<p>By the time the string includes 14 C&#39;s, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.</p>
<h2 id="remediation">Remediation</h2>
<p>Upgrade <code>path-to-regexp</code> to version 8.0.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/pillarjs/path-to-regexp/commit/29b96b4a1de52824e1ca0f49a701183cc4ed476f">GitHub Commit</a></li>
<li><a href="https://github.com/pillarjs/path-to-regexp/commit/60f2121e9b66b7b622cc01080df0aabda9eedee6">GitHub Commit</a></li>
<li><a href="https://blakeembrey.com/posts/2024-09-web-redos/">Vulnerability Write-up</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-JS-PATHTOREGEXP-7925106">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">Regular Expression Denial of Service (ReDoS)</h2>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:26:01 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:26:21 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:26:05 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:26:26 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Snyk test report</title>
<meta name="description" content="34 known vulnerabilities found in 236 vulnerable dependency paths.">
<meta name="description" content="33 known vulnerabilities found in 235 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">
@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:26:23 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:26:46 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -470,8 +470,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>34</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>236 vulnerable dependency paths</span></div>
<div class="meta-count"><span>33</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>235 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2278</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -2286,80 +2286,6 @@
<p><a href="https://snyk.io/vuln/SNYK-UBUNTU2204-CURL-7575743">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">CVE-2024-8096</h2>
<div class="card__section">
<div class="label label--medium">
<span class="label__text">medium severity</span>
</div>
<hr/>
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v2.10.16/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:22.04
</li>
<li class="card__meta__item">
Vulnerable module:
curl/libcurl3-gnutls
</li>
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v2.10.16, git@1:2.34.1-1ubuntu1.11 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>:
docker-image|quay.io/argoproj/argocd@v2.10.16
<span class="list-paths__item__arrow"></span>
git@1:2.34.1-1ubuntu1.11
<span class="list-paths__item__arrow"></span>
curl/libcurl3-gnutls@7.81.0-1ubuntu1.16
</span>
</li>
</ul><!-- .list-paths -->
</div><!-- .card__section -->
<hr/>
<!-- Overview -->
<h2 id="nvd-description">NVD Description</h2>
<p><strong><em>Note:</em></strong> <em>Versions mentioned in the description apply only to the upstream <code>curl</code> package and not the <code>curl</code> package as distributed by <code>Ubuntu</code>.</em>
<em>See <code>How to fix?</code> for <code>Ubuntu:22.04</code> relevant fixed versions and status.</em></p>
<p>When curl is told to use the Certificate Status Request TLS extension, often referred to as OCSP stapling, to verify that the server certificate is valid, it might fail to detect some OCSP problems and instead wrongly consider the response as fine. If the returned status reports another error than &#39;revoked&#39; (like for example &#39;unauthorized&#39;) it is not treated as a bad certficate.</p>
<h2 id="remediation">Remediation</h2>
<p>There is no fixed version for <code>Ubuntu:22.04</code> <code>curl</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-8096">http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-8096</a></li>
<li><a href="https://curl.se/docs/CVE-2024-8096.html">https://curl.se/docs/CVE-2024-8096.html</a></li>
<li><a href="https://curl.se/docs/CVE-2024-8096.json">https://curl.se/docs/CVE-2024-8096.json</a></li>
<li><a href="https://hackerone.com/reports/2669852">https://hackerone.com/reports/2669852</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-UBUNTU2204-CURL-7931918">More about this vulnerability</a></p>
</div>
</div><!-- .card -->
<div class="card card--vuln disclosure--not-new severity--low" data-snyk-test="low">
<h2 class="card__title">CVE-2023-7008</h2>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:26:27 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:26:51 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:25:35 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:25:50 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:25:43 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:26:00 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Snyk test report</title>
<meta name="description" content="6 known vulnerabilities found in 157 vulnerable dependency paths.">
<meta name="description" content="5 known vulnerabilities found in 154 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">
@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:23:42 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:23:52 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -467,8 +467,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>6</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>157 vulnerable dependency paths</span></div>
<div class="meta-count"><span>5</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>154 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2041</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -3139,173 +3139,6 @@
<p><a href="https://snyk.io/vuln/SNYK-GOLANG-GOLANGORGXNETHTTP2-6531285">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">Regular Expression Denial of Service (ReDoS)</h2>
<div class="card__section">
<div class="label label--medium">
<span class="label__text">medium severity</span>
</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:
path-to-regexp
</li>
<li class="card__meta__item">Introduced through:
argo-cd-ui@1.0.0, react-router@4.3.1 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-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.0
</span>
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
argo-cd-ui@1.0.0
<span class="list-paths__item__arrow"></span>
react-router-dom@4.3.1
<span class="list-paths__item__arrow"></span>
react-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.0
</span>
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
argo-cd-ui@1.0.0
<span class="list-paths__item__arrow"></span>
argo-ui@1.0.0
<span class="list-paths__item__arrow"></span>
react-router-dom@4.3.1
<span class="list-paths__item__arrow"></span>
react-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.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 Regular Expression Denial of Service (ReDoS) when including multiple regular expression parameters in a single segment, which will produce the regular expression <code>/^\/([^\/]+?)-([^\/]+?)\/?$/</code>, if two parameters within a single segment are separated by a character other than a <code>/</code> or <code>.</code>. Poor performance will block the event loop and can lead to a DoS.</p>
<p><strong>Note:</strong>
Version 0.1.10 is patched to mitigate this but is also vulnerable if custom regular expressions are used. Due to the existence of this attack vector, the Snyk security team have decided to err on the side of caution in considering the very widely-used v0 branch vulnerable, while the 8.0.0 release has completely eliminated the vulnerable functionality.</p>
<h2 id="workaround">Workaround</h2>
<p>This vulnerability can be avoided by using a custom regular expression for parameters after the first in a segment, which excludes <code>-</code> and <code>/</code>.</p>
<h2 id="poc">PoC</h2>
<pre><code class="language-js">/a${&#39;-a&#39;.repeat(8_000)}/a
</code></pre>
<h2 id="details">Details</h2>
<p>Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.</p>
<p>The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren&#39;t very intuitive and can ultimately end up making it easy for attackers to take your site down.</p>
<p>Lets take the following regular expression as an example:</p>
<pre><code class="language-js">regex = /A(B|C+)+D/
</code></pre>
<p>This regular expression accomplishes the following:</p>
<ul>
<li><code>A</code> The string must start with the letter &#39;A&#39;</li>
<li><code>(B|C+)+</code> The string must then follow the letter A with either the letter &#39;B&#39; or some number of occurrences of the letter &#39;C&#39; (the <code>+</code> matches one or more times). The <code>+</code> at the end of this section states that we can look for one or more matches of this section.</li>
<li><code>D</code> Finally, we ensure this section of the string ends with a &#39;D&#39;</li>
</ul>
<p>The expression would match inputs such as <code>ABBD</code>, <code>ABCCCCD</code>, <code>ABCBCCCD</code> and <code>ACCCCCD</code></p>
<p>It most cases, it doesn&#39;t take very long for a regex engine to find a match:</p>
<pre><code class="language-bash">$ time node -e &#39;/A(B|C+)+D/.test(&quot;ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD&quot;)&#39;
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e &#39;/A(B|C+)+D/.test(&quot;ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX&quot;)&#39;
1.79s user 0.02s system 99% cpu 1.812 total
</code></pre>
<p>The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.</p>
<p>Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesnt match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as <em>catastrophic backtracking</em>.</p>
<p>Let&#39;s look at how our expression runs into this problem, using a shorter string: &quot;ACCCX&quot;. While it seems fairly straightforward, there are still four different ways that the engine could match those three C&#39;s:</p>
<ol>
<li>CCC</li>
<li>CC+C</li>
<li>C+CC</li>
<li>C+C+C.</li>
</ol>
<p>The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use <a href="https://regex101.com/debugger">RegEx 101 debugger</a> to see the engine has to take a total of 38 steps before it can determine the string doesn&#39;t match.</p>
<p>From there, the number of steps the engine must use to validate a string just continues to grow.</p>
<table>
<thead>
<tr>
<th>String</th>
<th align="right">Number of C&#39;s</th>
<th align="right">Number of steps</th>
</tr>
</thead>
<tbody><tr>
<td>ACCCX</td>
<td align="right">3</td>
<td align="right">38</td>
</tr>
<tr>
<td>ACCCCX</td>
<td align="right">4</td>
<td align="right">71</td>
</tr>
<tr>
<td>ACCCCCX</td>
<td align="right">5</td>
<td align="right">136</td>
</tr>
<tr>
<td>ACCCCCCCCCCCCCCX</td>
<td align="right">14</td>
<td align="right">65,553</td>
</tr>
</tbody></table>
<p>By the time the string includes 14 C&#39;s, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.</p>
<h2 id="remediation">Remediation</h2>
<p>Upgrade <code>path-to-regexp</code> to version 8.0.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/pillarjs/path-to-regexp/commit/29b96b4a1de52824e1ca0f49a701183cc4ed476f">GitHub Commit</a></li>
<li><a href="https://github.com/pillarjs/path-to-regexp/commit/60f2121e9b66b7b622cc01080df0aabda9eedee6">GitHub Commit</a></li>
<li><a href="https://blakeembrey.com/posts/2024-09-web-redos/">Vulnerability Write-up</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-JS-PATHTOREGEXP-7925106">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">Denial of Service (DoS)</h2>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:23:48 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:23:58 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:23:53 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:24:05 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:24:16 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:24:29 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:23:20 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:23:27 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:23:29 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:23:37 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Snyk test report</title>
<meta name="description" content="4 known vulnerabilities found in 6 vulnerable dependency paths.">
<meta name="description" content="3 known vulnerabilities found in 3 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">
@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:21:28 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:21:25 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -467,8 +467,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>4</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>6 vulnerable dependency paths</span></div>
<div class="meta-count"><span>3</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>3 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2061</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -477,173 +477,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--medium" data-snyk-test="medium">
<h2 class="card__title">Regular Expression Denial of Service (ReDoS)</h2>
<div class="card__section">
<div class="label label--medium">
<span class="label__text">medium severity</span>
</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:
path-to-regexp
</li>
<li class="card__meta__item">Introduced through:
argo-cd-ui@1.0.0, react-router@4.3.1 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-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.0
</span>
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
argo-cd-ui@1.0.0
<span class="list-paths__item__arrow"></span>
react-router-dom@4.3.1
<span class="list-paths__item__arrow"></span>
react-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.0
</span>
</li>
<li>
<span class="list-paths__item__introduced"><em>Introduced through</em>:
argo-cd-ui@1.0.0
<span class="list-paths__item__arrow"></span>
argo-ui@1.0.0
<span class="list-paths__item__arrow"></span>
react-router-dom@4.3.1
<span class="list-paths__item__arrow"></span>
react-router@4.3.1
<span class="list-paths__item__arrow"></span>
path-to-regexp@1.8.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 Regular Expression Denial of Service (ReDoS) when including multiple regular expression parameters in a single segment, which will produce the regular expression <code>/^\/([^\/]+?)-([^\/]+?)\/?$/</code>, if two parameters within a single segment are separated by a character other than a <code>/</code> or <code>.</code>. Poor performance will block the event loop and can lead to a DoS.</p>
<p><strong>Note:</strong>
Version 0.1.10 is patched to mitigate this but is also vulnerable if custom regular expressions are used. Due to the existence of this attack vector, the Snyk security team have decided to err on the side of caution in considering the very widely-used v0 branch vulnerable, while the 8.0.0 release has completely eliminated the vulnerable functionality.</p>
<h2 id="workaround">Workaround</h2>
<p>This vulnerability can be avoided by using a custom regular expression for parameters after the first in a segment, which excludes <code>-</code> and <code>/</code>.</p>
<h2 id="poc">PoC</h2>
<pre><code class="language-js">/a${&#39;-a&#39;.repeat(8_000)}/a
</code></pre>
<h2 id="details">Details</h2>
<p>Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.</p>
<p>The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren&#39;t very intuitive and can ultimately end up making it easy for attackers to take your site down.</p>
<p>Lets take the following regular expression as an example:</p>
<pre><code class="language-js">regex = /A(B|C+)+D/
</code></pre>
<p>This regular expression accomplishes the following:</p>
<ul>
<li><code>A</code> The string must start with the letter &#39;A&#39;</li>
<li><code>(B|C+)+</code> The string must then follow the letter A with either the letter &#39;B&#39; or some number of occurrences of the letter &#39;C&#39; (the <code>+</code> matches one or more times). The <code>+</code> at the end of this section states that we can look for one or more matches of this section.</li>
<li><code>D</code> Finally, we ensure this section of the string ends with a &#39;D&#39;</li>
</ul>
<p>The expression would match inputs such as <code>ABBD</code>, <code>ABCCCCD</code>, <code>ABCBCCCD</code> and <code>ACCCCCD</code></p>
<p>It most cases, it doesn&#39;t take very long for a regex engine to find a match:</p>
<pre><code class="language-bash">$ time node -e &#39;/A(B|C+)+D/.test(&quot;ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD&quot;)&#39;
0.04s user 0.01s system 95% cpu 0.052 total
$ time node -e &#39;/A(B|C+)+D/.test(&quot;ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX&quot;)&#39;
1.79s user 0.02s system 99% cpu 1.812 total
</code></pre>
<p>The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.</p>
<p>Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesnt match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as <em>catastrophic backtracking</em>.</p>
<p>Let&#39;s look at how our expression runs into this problem, using a shorter string: &quot;ACCCX&quot;. While it seems fairly straightforward, there are still four different ways that the engine could match those three C&#39;s:</p>
<ol>
<li>CCC</li>
<li>CC+C</li>
<li>C+CC</li>
<li>C+C+C.</li>
</ol>
<p>The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use <a href="https://regex101.com/debugger">RegEx 101 debugger</a> to see the engine has to take a total of 38 steps before it can determine the string doesn&#39;t match.</p>
<p>From there, the number of steps the engine must use to validate a string just continues to grow.</p>
<table>
<thead>
<tr>
<th>String</th>
<th align="right">Number of C&#39;s</th>
<th align="right">Number of steps</th>
</tr>
</thead>
<tbody><tr>
<td>ACCCX</td>
<td align="right">3</td>
<td align="right">38</td>
</tr>
<tr>
<td>ACCCCX</td>
<td align="right">4</td>
<td align="right">71</td>
</tr>
<tr>
<td>ACCCCCX</td>
<td align="right">5</td>
<td align="right">136</td>
</tr>
<tr>
<td>ACCCCCCCCCCCCCCX</td>
<td align="right">14</td>
<td align="right">65,553</td>
</tr>
</tbody></table>
<p>By the time the string includes 14 C&#39;s, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.</p>
<h2 id="remediation">Remediation</h2>
<p>Upgrade <code>path-to-regexp</code> to version 8.0.0 or higher.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/pillarjs/path-to-regexp/commit/29b96b4a1de52824e1ca0f49a701183cc4ed476f">GitHub Commit</a></li>
<li><a href="https://github.com/pillarjs/path-to-regexp/commit/60f2121e9b66b7b622cc01080df0aabda9eedee6">GitHub Commit</a></li>
<li><a href="https://blakeembrey.com/posts/2024-09-web-redos/">Vulnerability Write-up</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-JS-PATHTOREGEXP-7925106">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">Denial of Service (DoS)</h2>
<div class="card__section">

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:21:35 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:21:34 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:21:38 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:21:39 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following path:</span>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:21:42 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:21:44 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Snyk test report</title>
<meta name="description" content="17 known vulnerabilities found in 81 vulnerable dependency paths.">
<meta name="description" content="16 known vulnerabilities found in 80 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">
@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:21:58 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:22:02 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>
@@ -470,8 +470,8 @@
</div>
<div class="meta-counts">
<div class="meta-count"><span>17</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>81 vulnerable dependency paths</span></div>
<div class="meta-count"><span>16</span> <span>known vulnerabilities</span></div>
<div class="meta-count"><span>80 vulnerable dependency paths</span></div>
<div class="meta-count"><span>2292</span> <span>dependencies</span></div>
</div><!-- .meta-counts -->
</div><!-- .layout-container--short -->
@@ -1435,7 +1435,7 @@
<em>See <code>How to fix?</code> for <code>Ubuntu:24.04</code> relevant fixed versions and status.</em></p>
<p>An issue was discovered in libexpat before 2.6.3. dtdCopy in xmlparse.c can have an integer overflow for nDefaultAtts on 32-bit platforms (where UINT_MAX equals SIZE_MAX).</p>
<h2 id="remediation">Remediation</h2>
<p>Upgrade <code>Ubuntu:24.04</code> <code>expat</code> to version 2.6.1-2ubuntu0.1 or higher.</p>
<p>There is no fixed version for <code>Ubuntu:24.04</code> <code>expat</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45491">http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45491</a></li>
@@ -1508,7 +1508,7 @@
<em>See <code>How to fix?</code> for <code>Ubuntu:24.04</code> relevant fixed versions and status.</em></p>
<p>An issue was discovered in libexpat before 2.6.3. xmlparse.c does not reject a negative length for XML_ParseBuffer.</p>
<h2 id="remediation">Remediation</h2>
<p>Upgrade <code>Ubuntu:24.04</code> <code>expat</code> to version 2.6.1-2ubuntu0.1 or higher.</p>
<p>There is no fixed version for <code>Ubuntu:24.04</code> <code>expat</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45490">http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45490</a></li>
@@ -1581,7 +1581,7 @@
<em>See <code>How to fix?</code> for <code>Ubuntu:24.04</code> relevant fixed versions and status.</em></p>
<p>An issue was discovered in libexpat before 2.6.3. nextScaffoldPart in xmlparse.c can have an integer overflow for m_groupSize on 32-bit platforms (where UINT_MAX equals SIZE_MAX).</p>
<h2 id="remediation">Remediation</h2>
<p>Upgrade <code>Ubuntu:24.04</code> <code>expat</code> to version 2.6.1-2ubuntu0.1 or higher.</p>
<p>There is no fixed version for <code>Ubuntu:24.04</code> <code>expat</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45492">http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-45492</a></li>
@@ -1595,80 +1595,6 @@
<p><a href="https://snyk.io/vuln/SNYK-UBUNTU2404-EXPAT-7885595">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">CVE-2024-8096</h2>
<div class="card__section">
<div class="label label--medium">
<span class="label__text">medium severity</span>
</div>
<hr/>
<ul class="card__meta">
<li class="card__meta__item">
Manifest file: quay.io/argoproj/argocd:v2.12.3/argoproj/argocd <span class="list-paths__item__arrow"></span> Dockerfile
</li>
<li class="card__meta__item">
Package Manager: ubuntu:24.04
</li>
<li class="card__meta__item">
Vulnerable module:
curl/libcurl3t64-gnutls
</li>
<li class="card__meta__item">Introduced through:
docker-image|quay.io/argoproj/argocd@v2.12.3, git@1:2.43.0-1ubuntu7.1 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>:
docker-image|quay.io/argoproj/argocd@v2.12.3
<span class="list-paths__item__arrow"></span>
git@1:2.43.0-1ubuntu7.1
<span class="list-paths__item__arrow"></span>
curl/libcurl3t64-gnutls@8.5.0-2ubuntu10.3
</span>
</li>
</ul><!-- .list-paths -->
</div><!-- .card__section -->
<hr/>
<!-- Overview -->
<h2 id="nvd-description">NVD Description</h2>
<p><strong><em>Note:</em></strong> <em>Versions mentioned in the description apply only to the upstream <code>curl</code> package and not the <code>curl</code> package as distributed by <code>Ubuntu</code>.</em>
<em>See <code>How to fix?</code> for <code>Ubuntu:24.04</code> relevant fixed versions and status.</em></p>
<p>When curl is told to use the Certificate Status Request TLS extension, often referred to as OCSP stapling, to verify that the server certificate is valid, it might fail to detect some OCSP problems and instead wrongly consider the response as fine. If the returned status reports another error than &#39;revoked&#39; (like for example &#39;unauthorized&#39;) it is not treated as a bad certficate.</p>
<h2 id="remediation">Remediation</h2>
<p>There is no fixed version for <code>Ubuntu:24.04</code> <code>curl</code>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-8096">http://people.ubuntu.com/~ubuntu-security/cve/CVE-2024-8096</a></li>
<li><a href="https://curl.se/docs/CVE-2024-8096.html">https://curl.se/docs/CVE-2024-8096.html</a></li>
<li><a href="https://curl.se/docs/CVE-2024-8096.json">https://curl.se/docs/CVE-2024-8096.json</a></li>
<li><a href="https://hackerone.com/reports/2669852">https://hackerone.com/reports/2669852</a></li>
</ul>
<hr/>
<div class="cta card__cta">
<p><a href="https://snyk.io/vuln/SNYK-UBUNTU2404-CURL-7931919">More about this vulnerability</a></p>
</div>
</div><!-- .card -->
<div class="card card--vuln disclosure--not-new severity--low" data-snyk-test="low">
<h2 class="card__title">Release of Invalid Pointer or Reference</h2>

View File

@@ -456,7 +456,7 @@
<div class="header-wrap">
<h1 class="project__header__title">Snyk test report</h1>
<p class="timestamp">September 15th 2024, 12:22:01 am (UTC+00:00)</p>
<p class="timestamp">September 8th 2024, 12:22:06 am (UTC+00:00)</p>
</div>
<div class="source-panel">
<span>Scanned the following paths:</span>

View File

@@ -8,7 +8,6 @@
| `ARGOCD_APP_NAMESPACE` | The destination namespace of the application. |
| `ARGOCD_APP_REVISION` | The resolved revision, e.g. `f913b6cbf58aa5ae5ca1f8a2b149477aebcbd9d8`. |
| `ARGOCD_APP_REVISION_SHORT` | The resolved short revision, e.g. `f913b6c`. |
| `ARGOCD_APP_REVISION_SHORT_8` | The resolved short revision with length 8, e.g. `f913b6cb`. |
| `ARGOCD_APP_SOURCE_PATH` | The path of the app within the source repo. |
| `ARGOCD_APP_SOURCE_REPO_URL` | The source repo URL. |
| `ARGOCD_APP_SOURCE_TARGET_REVISION` | The target revision from the spec, e.g. `master`. |

View File

@@ -30,6 +30,7 @@ argocd admin proj generate-spec PROJECT [flags]
--deny-namespaced-resource stringArray List of denied namespaced resources
--description string Project description
-d, --dest stringArray Permitted destination server and namespace (e.g. https://192.168.99.100:8443,default)
--dest-service-accounts stringArray Destination server, namespace and target service account (e.g. https://192.168.99.100:8443,default,default-sa)
-f, --file string Filename or URL to Kubernetes manifests for the project
-h, --help help for generate-spec
-i, --inline If set then generated resource is written back to the file specified in --file flag

View File

@@ -27,6 +27,7 @@ argocd proj create PROJECT [flags]
--deny-namespaced-resource stringArray List of denied namespaced resources
--description string Project description
-d, --dest stringArray Permitted destination server and namespace (e.g. https://192.168.99.100:8443,default)
--dest-service-accounts stringArray Destination server, namespace and target service account (e.g. https://192.168.99.100:8443,default,default-sa)
-f, --file string Filename or URL to Kubernetes manifests for the project
-h, --help help for create
--orphaned-resources Enables orphaned resources monitoring

View File

@@ -27,6 +27,7 @@ argocd proj set PROJECT [flags]
--deny-namespaced-resource stringArray List of denied namespaced resources
--description string Project description
-d, --dest stringArray Permitted destination server and namespace (e.g. https://192.168.99.100:8443,default)
--dest-service-accounts stringArray Destination server, namespace and target service account (e.g. https://192.168.99.100:8443,default,default-sa)
-h, --help help for set
--orphaned-resources Enables orphaned resources monitoring
--orphaned-resources-warn Specifies if applications should have a warning condition when orphaned resources detected

4
go.mod
View File

@@ -10,14 +10,14 @@ require (
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
github.com/alicebob/miniredis/v2 v2.33.0
github.com/antonmedv/expr v1.15.1
github.com/argoproj/gitops-engine v0.7.1-0.20240916204218-df9b446fd7d2
github.com/argoproj/gitops-engine v0.7.1-0.20240905010810-bd7681ae3f8b
github.com/argoproj/notifications-engine v0.4.1-0.20240606074338-0802cd427621
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1
github.com/aws/aws-sdk-go v1.55.5
github.com/bmatcuk/doublestar/v4 v4.6.1
github.com/bombsimon/logrusr/v2 v2.0.1
github.com/bradleyfalzon/ghinstallation/v2 v2.11.0
github.com/casbin/casbin/v2 v2.100.0
github.com/casbin/casbin/v2 v2.99.0
github.com/casbin/govaluate v1.2.0
github.com/cespare/xxhash/v2 v2.3.0
github.com/chainguard-dev/git-urls v1.0.2

8
go.sum
View File

@@ -83,8 +83,8 @@ github.com/antonmedv/expr v1.15.1/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4J
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE=
github.com/argoproj/gitops-engine v0.7.1-0.20240916204218-df9b446fd7d2 h1:vwgeR9wMFO/T+eZns5SKDyiiCJkMoYEU3NYGVCrr7FA=
github.com/argoproj/gitops-engine v0.7.1-0.20240916204218-df9b446fd7d2/go.mod h1:b1vuwkyMUszyUK+USUJqC8vJijnQsEPNDpC+sDdDLtM=
github.com/argoproj/gitops-engine v0.7.1-0.20240905010810-bd7681ae3f8b h1:wOPWJ5MBScQO767WpU55oUJDXObfvPL0EfAYWxogbSw=
github.com/argoproj/gitops-engine v0.7.1-0.20240905010810-bd7681ae3f8b/go.mod h1:b1vuwkyMUszyUK+USUJqC8vJijnQsEPNDpC+sDdDLtM=
github.com/argoproj/notifications-engine v0.4.1-0.20240606074338-0802cd427621 h1:Yg1nt+D2uDK1SL2jSlfukA4yc7db184TTN7iWy3voRE=
github.com/argoproj/notifications-engine v0.4.1-0.20240606074338-0802cd427621/go.mod h1:N0A4sEws2soZjEpY4hgZpQS8mRIEw6otzwfkgc3g9uQ=
github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 h1:qsHwwOJ21K2Ao0xPju1sNuqphyMnMYkyB3ZLoLtxWpo=
@@ -154,8 +154,8 @@ github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/casbin/casbin/v2 v2.100.0 h1:aeugSNjjHfCrgA22nHkVvw2xsscboHv5r0a13ljQKGQ=
github.com/casbin/casbin/v2 v2.100.0/go.mod h1:LO7YPez4dX3LgoTCqSQAleQDo0S0BeZBDxYnPUl95Ng=
github.com/casbin/casbin/v2 v2.99.0 h1:Y993vfRenh8Xtb4XVaK8KeYJTjD4Zn1XVewGszhzk1E=
github.com/casbin/casbin/v2 v2.99.0/go.mod h1:LO7YPez4dX3LgoTCqSQAleQDo0S0BeZBDxYnPUl95Ng=
github.com/casbin/govaluate v1.2.0 h1:wXCXFmqyY+1RwiKfYo3jMKyrtZmOL3kHwaqDyCPOYak=
github.com/casbin/govaluate v1.2.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=

View File

@@ -0,0 +1 @@
1bc3f354f7ce4d7fd9cfa5bcc701c1f32c88d27076d96c2792d5b5226062aee5 helm-v3.15.4-darwin-amd64.tar.gz

View File

@@ -0,0 +1 @@
88115846a1fb58f8eb8f64fec5c343d95ca394f1be811602fa54a887c98730ac helm-v3.15.4-darwin-arm64.tar.gz

View File

@@ -0,0 +1 @@
11400fecfc07fd6f034863e4e0c4c4445594673fd2a129e701fe41f31170cfa9 helm-v3.15.4-linux-amd64.tar.gz

View File

@@ -0,0 +1 @@
fa419ecb139442e8a594c242343fafb7a46af3af34041c4eac1efcc49d74e626 helm-v3.15.4-linux-arm64.tar.gz

View File

@@ -0,0 +1 @@
e4efce93723f52dd858e9046ea836c9c75f346facce1b87b8cf78c817b97e6ac helm-v3.15.4-linux-ppc64le.tar.gz

View File

@@ -0,0 +1 @@
c6e0cdea598196895ac7b627ce972699ef9f06b0eba51dc4db7cc21b3369f24a helm-v3.15.4-linux-s390x.tar.gz

View File

@@ -11,7 +11,7 @@
# Use ./hack/installers/checksums/add-helm-checksums.sh and
# add-kustomize-checksums.sh to help download checksums.
###############################################################################
helm3_version=3.15.2
helm3_version=3.15.4
kubectl_version=1.17.8
kubectx_version=0.6.3
kustomize5_version=5.4.3

View File

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

View File

@@ -15,6 +15,7 @@ rules:
- delete # supports deletion a live object in UI
- get # supports viewing live object manifest in UI
- patch # supports `argocd app patch`
- list # supports `argocd appset generate` with cluster generator
- apiGroups:
- ""
resources:

View File

@@ -21735,7 +21735,7 @@ spec:
sync operation.
properties:
defaultServiceAccount:
description: ServiceAccountName to be used for impersonation
description: DefaultServiceAccount to be used for impersonation
during the sync operation
type: string
namespace:
@@ -21746,6 +21746,9 @@ spec:
description: Server specifies the URL of the target cluster's
Kubernetes control plane API.
type: string
required:
- defaultServiceAccount
- server
type: object
type: array
destinations:
@@ -22558,7 +22561,7 @@ spec:
key: applicationsetcontroller.webhook.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -22676,7 +22679,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -22929,7 +22932,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -22981,7 +22984,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -23253,7 +23256,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -12,4 +12,4 @@ resources:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: latest
newTag: v2.13.0-rc3

View File

@@ -95,7 +95,7 @@ spec:
sync operation.
properties:
defaultServiceAccount:
description: ServiceAccountName to be used for impersonation
description: DefaultServiceAccount to be used for impersonation
during the sync operation
type: string
namespace:
@@ -106,6 +106,9 @@ spec:
description: Server specifies the URL of the target cluster's
Kubernetes control plane API.
type: string
required:
- defaultServiceAccount
- server
type: object
type: array
destinations:

View File

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

View File

@@ -21735,7 +21735,7 @@ spec:
sync operation.
properties:
defaultServiceAccount:
description: ServiceAccountName to be used for impersonation
description: DefaultServiceAccount to be used for impersonation
during the sync operation
type: string
namespace:
@@ -21746,6 +21746,9 @@ spec:
description: Server specifies the URL of the target cluster's
Kubernetes control plane API.
type: string
required:
- defaultServiceAccount
- server
type: object
type: array
destinations:
@@ -22463,6 +22466,7 @@ rules:
- delete
- get
- patch
- list
- apiGroups:
- ""
resources:
@@ -23901,7 +23905,7 @@ spec:
key: applicationsetcontroller.webhook.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -24036,7 +24040,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -24124,7 +24128,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -24243,7 +24247,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -24524,7 +24528,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -24576,7 +24580,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -24930,7 +24934,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -25238,7 +25242,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -1694,7 +1694,7 @@ spec:
key: applicationsetcontroller.webhook.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -1829,7 +1829,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1917,7 +1917,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -2036,7 +2036,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -2317,7 +2317,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -2369,7 +2369,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -2723,7 +2723,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -3031,7 +3031,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

22
manifests/install.yaml generated
View File

@@ -21735,7 +21735,7 @@ spec:
sync operation.
properties:
defaultServiceAccount:
description: ServiceAccountName to be used for impersonation
description: DefaultServiceAccount to be used for impersonation
during the sync operation
type: string
namespace:
@@ -21746,6 +21746,9 @@ spec:
description: Server specifies the URL of the target cluster's
Kubernetes control plane API.
type: string
required:
- defaultServiceAccount
- server
type: object
type: array
destinations:
@@ -22430,6 +22433,7 @@ rules:
- delete
- get
- patch
- list
- apiGroups:
- ""
resources:
@@ -23018,7 +23022,7 @@ spec:
key: applicationsetcontroller.webhook.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -23153,7 +23157,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -23241,7 +23245,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -23341,7 +23345,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -23594,7 +23598,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -23646,7 +23650,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -23998,7 +24002,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -24306,7 +24310,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -811,7 +811,7 @@ spec:
key: applicationsetcontroller.webhook.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -946,7 +946,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1034,7 +1034,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -1134,7 +1134,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -1387,7 +1387,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1439,7 +1439,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -1791,7 +1791,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2099,7 +2099,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.13.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -6,15 +6,22 @@ import (
"strconv"
"strings"
"github.com/argoproj/argo-cd/v2/util/git"
"github.com/argoproj/argo-cd/v2/util/glob"
globutil "github.com/gobwas/glob"
"github.com/google/go-cmp/cmp"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/argoproj/argo-cd/v2/util/git"
"github.com/argoproj/argo-cd/v2/util/glob"
)
const (
// serviceAccountDisallowedCharSet contains the characters that are not allowed to be present
// in a DefaultServiceAccount configured for a DestinationServiceAccount
serviceAccountDisallowedCharSet = "!*[]{}\\/"
)
type ErrApplicationNotAllowedToUseProject struct {
@@ -267,12 +274,27 @@ func (p *AppProject) ValidateProject() error {
destServiceAccts := make(map[string]bool)
for _, destServiceAcct := range p.Spec.DestinationServiceAccounts {
if destServiceAcct.Server == "!*" {
return status.Errorf(codes.InvalidArgument, "server has an invalid format, '!*'")
if strings.Contains(destServiceAcct.Server, "!") {
return status.Errorf(codes.InvalidArgument, "server has an invalid format, '%s'", destServiceAcct.Server)
}
if destServiceAcct.Namespace == "!*" {
return status.Errorf(codes.InvalidArgument, "namespace has an invalid format, '!*'")
if strings.Contains(destServiceAcct.Namespace, "!") {
return status.Errorf(codes.InvalidArgument, "namespace has an invalid format, '%s'", destServiceAcct.Namespace)
}
if strings.Trim(destServiceAcct.DefaultServiceAccount, " ") == "" ||
strings.ContainsAny(destServiceAcct.DefaultServiceAccount, serviceAccountDisallowedCharSet) {
return status.Errorf(codes.InvalidArgument, "defaultServiceAccount has an invalid format, '%s'", destServiceAcct.DefaultServiceAccount)
}
_, err := globutil.Compile(destServiceAcct.Server)
if err != nil {
return status.Errorf(codes.InvalidArgument, "server has an invalid format, '%s'", destServiceAcct.Server)
}
_, err = globutil.Compile(destServiceAcct.Namespace)
if err != nil {
return status.Errorf(codes.InvalidArgument, "namespace has an invalid format, '%s'", destServiceAcct.Namespace)
}
key := fmt.Sprintf("%s/%s", destServiceAcct.Server, destServiceAcct.Namespace)

View File

@@ -156,7 +156,7 @@ message ApplicationDestinationServiceAccount {
// Namespace specifies the target namespace for the application's resources.
optional string namespace = 2;
// ServiceAccountName to be used for impersonation during the sync operation
// DefaultServiceAccount to be used for impersonation during the sync operation
optional string defaultServiceAccount = 3;
}

View File

@@ -2767,11 +2767,11 @@ type KustomizeOptions struct {
// ApplicationDestinationServiceAccount holds information about the service account to be impersonated for the application sync operation.
type ApplicationDestinationServiceAccount struct {
// Server specifies the URL of the target cluster's Kubernetes control plane API.
Server string `json:"server,omitempty" protobuf:"bytes,1,opt,name=server"`
Server string `json:"server" protobuf:"bytes,1,opt,name=server"`
// Namespace specifies the target namespace for the application's resources.
Namespace string `json:"namespace,omitempty" protobuf:"bytes,2,opt,name=namespace"`
// ServiceAccountName to be used for impersonation during the sync operation
DefaultServiceAccount string `json:"defaultServiceAccount,omitempty" protobuf:"bytes,3,opt,name=defaultServiceAccount"`
// DefaultServiceAccount to be used for impersonation during the sync operation
DefaultServiceAccount string `json:"defaultServiceAccount" protobuf:"bytes,3,opt,name=defaultServiceAccount"`
}
// CascadedDeletion indicates if the deletion finalizer is set and controller should delete the application and it's cascaded resources

View File

@@ -3959,3 +3959,158 @@ func TestApplicationTree_Merge(t *testing.T) {
},
}, tree)
}
func TestAppProject_ValidateDestinationServiceAccount(t *testing.T) {
testData := []struct {
server string
namespace string
defaultServiceAccount string
expectedErrMsg string
}{
{
// Given, a project
// When, a default destination service account with all valid fields is added to it,
// Then, there is no error.
server: "https://192.168.99.100:8443",
namespace: "test-ns",
defaultServiceAccount: "test-sa",
expectedErrMsg: "",
},
{
// Given, a project
// When, a default destination service account with negation glob pattern for server is added,
// Then, there is an error with appropriate message.
server: "!abc",
namespace: "test-ns",
defaultServiceAccount: "test-sa",
expectedErrMsg: "server has an invalid format, '!abc'",
},
{
// Given, a project
// When, a default destination service account with empty namespace is added to it,
// Then, there is no error.
server: "https://192.168.99.100:8443",
namespace: "",
defaultServiceAccount: "test-sa",
expectedErrMsg: "",
},
{
// Given, a project,
// When, a default destination service account with negation glob pattern for server is added,
// Then, there is an error with appropriate message.
server: "!*",
namespace: "test-ns",
defaultServiceAccount: "test-sa",
expectedErrMsg: "server has an invalid format, '!*'",
},
{
// Given, a project,
// When, a default destination service account with negation glob pattern for namespace is added,
// Then, there is an error with appropriate message.
server: "https://192.168.99.100:8443",
namespace: "!*",
defaultServiceAccount: "test-sa",
expectedErrMsg: "namespace has an invalid format, '!*'",
},
{
// Given, a project,
// When, a default destination service account with negation glob pattern for namespace is added,
// Then, there is an error with appropriate message.
server: "https://192.168.99.100:8443",
namespace: "!abc",
defaultServiceAccount: "test-sa",
expectedErrMsg: "namespace has an invalid format, '!abc'",
},
{
// Given, a project,
// When, a default destination service account with empty service account is added,
// Then, there is an error with appropriate message.
server: "https://192.168.99.100:8443",
namespace: "test-ns",
defaultServiceAccount: "",
expectedErrMsg: "defaultServiceAccount has an invalid format, ''",
},
{
// Given, a project,
// When, a default destination service account with service account having just white spaces is added,
// Then, there is an error with appropriate message.
server: "https://192.168.99.100:8443",
namespace: "test-ns",
defaultServiceAccount: " ",
expectedErrMsg: "defaultServiceAccount has an invalid format, ' '",
},
{
// Given, a project,
// When, a default destination service account with service account having backwards slash char is added,
// Then, there is an error with appropriate message.
server: "https://192.168.99.100:8443",
namespace: "test-ns",
defaultServiceAccount: "test\\sa",
expectedErrMsg: "defaultServiceAccount has an invalid format, 'test\\sa'",
},
{
// Given, a project,
// When, a default destination service account with service account having forward slash char is added,
// Then, there is an error with appropriate message.
server: "https://192.168.99.100:8443",
namespace: "test-ns",
defaultServiceAccount: "test/sa",
expectedErrMsg: "defaultServiceAccount has an invalid format, 'test/sa'",
},
{
// Given, a project,
// When, a default destination service account with service account having square braces char is added,
// Then, there is an error with appropriate message.
server: "https://192.168.99.100:8443",
namespace: "test-ns",
defaultServiceAccount: "[test-sa]",
expectedErrMsg: "defaultServiceAccount has an invalid format, '[test-sa]'",
},
{
// Given, a project,
// When, a default destination service account with service account having curly braces char is added,
// Then, there is an error with appropriate message.
server: "https://192.168.99.100:8443",
namespace: "test-ns",
defaultServiceAccount: "{test-sa}",
expectedErrMsg: "defaultServiceAccount has an invalid format, '{test-sa}'",
},
{
// Given, a project,
// When, a default destination service account with service account having curly braces char is added,
// Then, there is an error with appropriate message.
server: "[[ech*",
namespace: "test-ns",
defaultServiceAccount: "test-sa",
expectedErrMsg: "server has an invalid format, '[[ech*'",
},
{
// Given, a project,
// When, a default destination service account with service account having curly braces char is added,
// Then, there is an error with appropriate message.
server: "https://192.168.99.100:8443",
namespace: "[[ech*",
defaultServiceAccount: "test-sa",
expectedErrMsg: "namespace has an invalid format, '[[ech*'",
},
}
for _, data := range testData {
proj := AppProject{
Spec: AppProjectSpec{
DestinationServiceAccounts: []ApplicationDestinationServiceAccount{
{
Server: data.server,
Namespace: data.namespace,
DefaultServiceAccount: data.defaultServiceAccount,
},
},
},
}
err := proj.ValidateProject()
if data.expectedErrMsg == "" {
require.NoError(t, err)
} else {
require.ErrorContains(t, err, data.expectedErrMsg)
}
}
}

View File

@@ -1511,27 +1511,21 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string,
}
func newEnv(q *apiclient.ManifestRequest, revision string) *v1alpha1.Env {
shortRevision := shortenRevision(revision, 7)
shortRevision8 := shortenRevision(revision, 8)
shortRevision := revision
if len(shortRevision) > 7 {
shortRevision = shortRevision[:7]
}
return &v1alpha1.Env{
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: q.AppName},
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAMESPACE", Value: q.Namespace},
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_REVISION", Value: revision},
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_REVISION_SHORT", Value: shortRevision},
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_REVISION_SHORT_8", Value: shortRevision8},
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_REPO_URL", Value: q.Repo.Repo},
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_PATH", Value: q.ApplicationSource.Path},
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_TARGET_REVISION", Value: q.ApplicationSource.TargetRevision},
}
}
func shortenRevision(revision string, length int) string {
if len(revision) > length {
return revision[:length]
}
return revision
}
func newEnvRepoQuery(q *apiclient.RepoServerAppDetailsQuery, revision string) *v1alpha1.Env {
return &v1alpha1.Env{
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: q.AppName},

View File

@@ -1817,7 +1817,6 @@ func Test_newEnv(t *testing.T) {
&argoappv1.EnvEntry{Name: "ARGOCD_APP_NAMESPACE", Value: "my-namespace"},
&argoappv1.EnvEntry{Name: "ARGOCD_APP_REVISION", Value: "my-revision"},
&argoappv1.EnvEntry{Name: "ARGOCD_APP_REVISION_SHORT", Value: "my-revi"},
&argoappv1.EnvEntry{Name: "ARGOCD_APP_REVISION_SHORT_8", Value: "my-revis"},
&argoappv1.EnvEntry{Name: "ARGOCD_APP_SOURCE_REPO_URL", Value: "https://github.com/my-org/my-repo"},
&argoappv1.EnvEntry{Name: "ARGOCD_APP_SOURCE_PATH", Value: "my-path"},
&argoappv1.EnvEntry{Name: "ARGOCD_APP_SOURCE_TARGET_REVISION", Value: "my-target-revision"},

View File

@@ -14,10 +14,10 @@ if obj.status.status ~= nil then
-- "root" policy
for i, entry in ipairs(obj.status.status) do
if entry.compliant ~= "Compliant" then
noncompliants[i] = entry.clustername
table.insert(noncompliants, entry.clustername)
end
end
if table.getn(noncompliants) == 0 then
if #noncompliants == 0 then
hs.message = "All clusters are compliant"
else
hs.message = "NonCompliant clusters: " .. table.concat(noncompliants, ", ")
@@ -26,10 +26,10 @@ elseif obj.status.details ~= nil then
-- "replicated" policy
for i, entry in ipairs(obj.status.details) do
if entry.compliant ~= "Compliant" then
noncompliants[i] = entry.templateMeta.name
table.insert(noncompliants, entry.templateMeta.name)
end
end
if table.getn(noncompliants) == 0 then
if #noncompliants == 0 then
hs.message = "All templates are compliant"
else
hs.message = "NonCompliant templates: " .. table.concat(noncompliants, ", ")

View File

@@ -0,0 +1,88 @@
apiVersion: policy.open-cluster-management.io/v1
kind: Policy
metadata:
name: open-cluster-management-global-set.argo-example
namespace: local-cluster
labels:
policy.open-cluster-management.io/cluster-name: local-cluster
policy.open-cluster-management.io/cluster-namespace: local-cluster
policy.open-cluster-management.io/root-policy: open-cluster-management-global-set.argo-example
spec:
disabled: false
policy-templates:
- objectDefinition:
apiVersion: policy.open-cluster-management.io/v1
kind: ConfigurationPolicy
metadata:
name: example-namespace
spec:
object-templates:
- complianceType: musthave
objectDefinition:
apiVersion: v1
kind: Namespace
metadata:
name: example
remediationAction: inform
severity: low
- objectDefinition:
apiVersion: policy.open-cluster-management.io/v1
kind: ConfigurationPolicy
metadata:
name: example-pod
spec:
namespaceSelector:
exclude:
- kube-*
include:
- default
object-templates:
- complianceType: musthave
objectDefinition:
apiVersion: v1
kind: Pod
metadata:
name: foobar
spec:
containers:
- image: 'registry.redhat.io/rhel9/httpd-24:latest'
name: httpd
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
privileged: false
runAsNonRoot: true
remediationAction: enforce
severity: low
status:
compliant: NonCompliant
details:
- compliant: Compliant
history:
- eventName: open-cluster-management-global-set.argo-example.17e7034c879045a3
lastTimestamp: '2024-07-30T14:16:49Z'
message: 'Compliant; notification - pods [foobar] was created successfully in namespace default'
templateMeta:
creationTimestamp: null
name: example-foo
- compliant: NonCompliant
history:
- eventName: open-cluster-management-global-set.argo-example.17e701cc5101e3a4
lastTimestamp: '2024-07-30T13:49:19Z'
message: 'NonCompliant; violation - namespaces [example] not found'
templateMeta:
creationTimestamp: null
name: example-namespace
- compliant: Compliant
history:
- eventName: open-cluster-management-global-set.argo-example.17e7034c879045a3
lastTimestamp: '2024-07-30T14:16:49Z'
message: 'Compliant; notification - pods [foobar] was created successfully in namespace default'
- eventName: open-cluster-management-global-set.argo-example.17e7020b47782ddc
lastTimestamp: '2024-07-30T13:53:49Z'
message: 'NonCompliant; violation - pods [foobar] not found in namespace default'
templateMeta:
creationTimestamp: null
name: example-pod

View File

@@ -1,50 +1,59 @@
-- isInferenceServiceInRawDeploymentMode determines if the inference service deployed in RawDeployment mode
-- KServe v12 and above supports Rawdeployment for Inference graphs. For Inference services, KServe has supported RawDeployment model since [v0.7.0](https://github.com/kserve/kserve/releases/tag/v0.7.0).
function isInferenceServiceInRawDeploymentMode(obj)
if obj.metadata.annotations == nil then
return false
end
local deploymentMode = obj.metadata.annotations["serving.kserve.io/deploymentMode"]
return deploymentMode ~= nil and deploymentMode == "RawDeployment"
end
local health_status = {}
health_status.status = "Progressing"
health_status.message = "Waiting for status update."
if obj.status ~= nil and obj.status.conditions ~= nil then
local status_true = 0
health_status.message = "Waiting for InferenceService to report status..."
if obj.status ~= nil then
local progressing = false
local degraded = false
local status_false = 0
local status_unknown = 0
health_status.message = ""
for i, condition in pairs(obj.status.conditions) do
if condition.status == "True" and (condition.type == "IngressReady" or condition.type == "PredictorConfigurationReady" or condition.type == "PredictorReady" or condition.type == "PredictorRouteReady" or condition.type == "Ready") then
status_true = status_true + 1
elseif condition.status == "False" or condition.status == "Unknown" then
msg = condition.type .. " is " .. condition.status
if condition.reason ~= nil and condition.reason ~= "" then
msg = msg .. ", since " .. condition.reason .. "."
end
if condition.message ~= nil and condition.message ~= "" then
msg = msg .. " " .. condition.message
end
health_status.message = health_status.message .. msg .. "\n"
if condition.status == "False" then
status_false = status_false + 1
local msg = ""
if obj.status.modelStatus ~= nil then
if obj.status.modelStatus.transitionStatus ~= "UpToDate" then
if obj.status.modelStatus.transitionStatus == "InProgress" then
progressing = true
else
status_unknown = status_unknown + 1
degraded = true
end
msg = msg .. "0: transitionStatus | " .. obj.status.modelStatus.transitionStatus
end
end
if ((isInferenceServiceInRawDeploymentMode(obj) and status_true == 3) or status_true == 5) and status_false == 0 and status_unknown == 0 then
health_status.message = "Inference Service is healthy."
health_status.status = "Healthy"
return health_status
elseif status_false > 0 then
health_status.status = "Degraded"
return health_status
else
health_status.status = "Progressing"
return health_status
if obj.status.conditions ~= nil then
for i, condition in pairs(obj.status.conditions) do
if condition.status == "Unknown" then
status_unknown = status_unknown + 1
elseif condition.status == "False" then
status_false = status_false + 1
end
if condition.status ~= "True" then
msg = msg .. " | " .. i .. ": " .. condition.type .. " | " .. condition.status
if condition.reason ~= nil and condition.reason ~= "" then
msg = msg .. " | " .. condition.reason
end
if condition.message ~= nil and condition.message ~= "" then
msg = msg .. " | " .. condition.message
end
end
end
if progressing == false and degraded == false and status_unknown == 0 and status_false == 0 then
health_status.status = "Healthy"
msg = "InferenceService is healthy."
elseif degraded == false and status_unknown >= 0 then
health_status.status = "Progressing"
else
health_status.status = "Degraded"
end
health_status.message = msg
end
end
return health_status
return health_status

View File

@@ -1,17 +1,41 @@
tests:
- healthStatus:
status: Progressing
message: "PredictorConfigurationReady is Unknown\nPredictorReady is Unknown, since RevisionMissing. Configuration \"hello-world-predictor-default\" is waiting for a Revision to become ready.\nPredictorRouteReady is Unknown, since RevisionMissing. Configuration \"hello-world-predictor-default\" is waiting for a Revision to become ready.\nReady is Unknown, since RevisionMissing. Configuration \"hello-world-predictor-default\" is waiting for a Revision to become ready.\n"
message: ' | 1: PredictorConfigurationReady | Unknown | 2: PredictorReady | Unknown | RevisionMissing | Configuration "hello-world-predictor-default" is waiting for a Revision to become ready. | 3: PredictorRouteReady | Unknown | RevisionMissing | Configuration "hello-world-predictor-default" is waiting for a Revision to become ready. | 4: Ready | Unknown | RevisionMissing | Configuration "hello-world-predictor-default" is waiting for a Revision to become ready.'
inputPath: testdata/progressing.yaml
- healthStatus:
status: Progressing
message: '0: transitionStatus | InProgress | 1: LatestDeploymentReady | Unknown | PredictorConfigurationReady not ready | 2: PredictorConfigurationReady | Unknown | 3: PredictorReady | Unknown | RevisionMissing | Configuration "helloworld-predictor" is waiting for a Revision to become ready. | 4: PredictorRouteReady | Unknown | RevisionMissing | Configuration "helloworld-predictor" is waiting for a Revision to become ready. | 5: Ready | Unknown | RevisionMissing | Configuration "helloworld-predictor" is waiting for a Revision to become ready. | 6: RoutesReady | Unknown | PredictorRouteReady not ready'
inputPath: testdata/progressing_ocp.yaml
- healthStatus:
status: Progressing
message: "0: transitionStatus | InProgress | 1: PredictorReady | False | 2: Ready | False"
inputPath: testdata/progressing_modelmesh.yaml
- healthStatus:
status: Degraded
message: "IngressReady is False, since Predictor ingress not created.\nPredictorConfigurationReady is False, since RevisionFailed. Revision \"helloworld-00002\" failed with message: Container failed with: container exited with no error.\nPredictorReady is False, since RevisionFailed. Revision \"helloworld-00002\" failed with message: Container failed with: container exited with no error.\nReady is False, since Predictor ingress not created.\n"
message: '0: transitionStatus | BlockedByFailedLoad | 1: IngressReady | False | Predictor ingress not created | 2: PredictorConfigurationReady | False | RevisionFailed | Revision "helloworld-00002" failed with message: Container failed with: container exited with no error. | 3: PredictorReady | False | RevisionFailed | Revision "helloworld-00002" failed with message: Container failed with: container exited with no error. | 5: Ready | False | Predictor ingress not created'
inputPath: testdata/degraded.yaml
- healthStatus:
status: Degraded
message: '0: transitionStatus | BlockedByFailedLoad | 1: LatestDeploymentReady | False | PredictorConfigurationReady not ready | 2: PredictorConfigurationReady | False | RevisionFailed | Revision "helloworld-predictor-00002" failed with message: . | 3: PredictorReady | False | RevisionMissing | Configuration "helloworld-predictor" does not have any ready Revision. | 4: PredictorRouteReady | False | RevisionMissing | Configuration "helloworld-predictor" does not have any ready Revision. | 5: Ready | False | RevisionMissing | Configuration "helloworld-predictor" does not have any ready Revision. | 6: RoutesReady | False | PredictorRouteReady not ready'
inputPath: testdata/degraded_ocp.yaml
- healthStatus:
status: Degraded
message: "0: transitionStatus | BlockedByFailedLoad"
inputPath: testdata/degraded_modelmesh.yaml
- healthStatus:
status: Healthy
message: Inference Service is healthy.
message: InferenceService is healthy.
inputPath: testdata/healthy.yaml
- healthStatus:
status: Healthy
message: Inference Service is healthy.
message: InferenceService is healthy.
inputPath: testdata/healthy_ocp.yaml
- healthStatus:
status: Healthy
message: InferenceService is healthy.
inputPath: testdata/healthy_modelmesh.yaml
- healthStatus:
status: Healthy
message: InferenceService is healthy.
inputPath: testdata/healthy_raw.yaml

View File

@@ -28,3 +28,5 @@ status:
reason: Predictor ingress not created
status: "False"
type: Ready
modelStatus:
transitionStatus: BlockedByFailedLoad

View File

@@ -0,0 +1,16 @@
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: helloworld
namespace: default
spec: {}
status:
conditions:
- lastTransitionTime: '2024-05-30T22:43:16Z'
status: 'True'
type: PredictorReady
- lastTransitionTime: '2024-05-30T22:43:16Z'
status: 'True'
type: Ready
modelStatus:
transitionStatus: BlockedByFailedLoad

View File

@@ -0,0 +1,42 @@
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: helloworld
namespace: default
spec: {}
status:
conditions:
- lastTransitionTime: '2024-05-30T23:03:45Z'
reason: PredictorConfigurationReady not ready
severity: Info
status: 'False'
type: LatestDeploymentReady
- lastTransitionTime: '2024-05-30T23:03:45Z'
message: 'Revision "helloworld-predictor-00002" failed with message: .'
reason: RevisionFailed
severity: Info
status: 'False'
type: PredictorConfigurationReady
- lastTransitionTime: '2024-05-30T23:03:45Z'
message: Configuration "helloworld-predictor" does not have any ready Revision.
reason: RevisionMissing
status: 'False'
type: PredictorReady
- lastTransitionTime: '2024-05-30T23:03:45Z'
message: Configuration "helloworld-predictor" does not have any ready Revision.
reason: RevisionMissing
severity: Info
status: 'False'
type: PredictorRouteReady
- lastTransitionTime: '2024-05-30T23:03:45Z'
message: Configuration "helloworld-predictor" does not have any ready Revision.
reason: RevisionMissing
status: 'False'
type: Ready
- lastTransitionTime: '2024-05-30T23:03:45Z'
reason: PredictorRouteReady not ready
severity: Info
status: 'False'
type: RoutesReady
modelStatus:
transitionStatus: BlockedByFailedLoad

View File

@@ -0,0 +1,16 @@
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: helloworld
namespace: default
spec: {}
status:
conditions:
- lastTransitionTime: '2024-05-30T22:43:16Z'
status: 'True'
type: PredictorReady
- lastTransitionTime: '2024-05-30T22:43:16Z'
status: 'True'
type: Ready
modelStatus:
transitionStatus: UpToDate

View File

@@ -0,0 +1,35 @@
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: helloworld
namespace: default
spec: {}
status:
conditions:
- lastTransitionTime: '2024-05-30T22:14:31Z'
status: 'True'
type: IngressReady
- lastTransitionTime: '2024-05-30T22:14:30Z'
severity: Info
status: 'True'
type: LatestDeploymentReady
- lastTransitionTime: '2024-05-30T22:14:30Z'
severity: Info
status: 'True'
type: PredictorConfigurationReady
- lastTransitionTime: '2024-05-30T22:14:31Z'
status: 'True'
type: PredictorReady
- lastTransitionTime: '2024-05-30T22:14:31Z'
severity: Info
status: 'True'
type: PredictorRouteReady
- lastTransitionTime: '2024-05-30T22:14:31Z'
status: 'True'
type: Ready
- lastTransitionTime: '2024-05-30T22:14:31Z'
severity: Info
status: 'True'
type: RoutesReady
modelStatus:
transitionStatus: UpToDate

View File

@@ -0,0 +1,16 @@
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: helloworld
namespace: default
spec: {}
status:
conditions:
- lastTransitionTime: '2024-05-30T22:43:16Z'
status: 'False'
type: PredictorReady
- lastTransitionTime: '2024-05-30T22:43:16Z'
status: 'False'
type: Ready
modelStatus:
transitionStatus: InProgress

View File

@@ -0,0 +1,40 @@
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: helloworld
namespace: default
spec: {}
status:
conditions:
- lastTransitionTime: '2024-05-30T22:29:46Z'
reason: PredictorConfigurationReady not ready
severity: Info
status: Unknown
type: LatestDeploymentReady
- lastTransitionTime: '2024-05-30T22:29:46Z'
severity: Info
status: Unknown
type: PredictorConfigurationReady
- lastTransitionTime: '2024-05-30T22:29:46Z'
message: Configuration "helloworld-predictor" is waiting for a Revision to become ready.
reason: RevisionMissing
status: Unknown
type: PredictorReady
- lastTransitionTime: '2024-05-30T22:29:46Z'
message: Configuration "helloworld-predictor" is waiting for a Revision to become ready.
reason: RevisionMissing
severity: Info
status: Unknown
type: PredictorRouteReady
- lastTransitionTime: '2024-05-30T22:29:46Z'
message: Configuration "helloworld-predictor" is waiting for a Revision to become ready.
reason: RevisionMissing
status: Unknown
type: Ready
- lastTransitionTime: '2024-05-30T22:29:46Z'
reason: PredictorRouteReady not ready
severity: Info
status: Unknown
type: RoutesReady
modelStatus:
transitionStatus: InProgress

View File

@@ -33,6 +33,12 @@ const (
DefaultIdleConnectionTimeout = 60 * time.Second
DefaultMaxIdleConnections = 30
// HeaderArgoCDNamespace defines the namespace of the
// argo control plane to be passed to the extension handler.
// Example:
// Argocd-Namespace: "namespace"
HeaderArgoCDNamespace = "Argocd-Namespace"
// HeaderArgoCDApplicationName defines the name of the
// expected application header to be passed to the extension
// handler. The header value must follow the format:
@@ -333,6 +339,7 @@ type RbacEnforcer interface {
// and handling proxy extensions.
type Manager struct {
log *log.Entry
namespace string
settings SettingsGetter
application ApplicationGetter
project ProjectGetter
@@ -355,9 +362,10 @@ type ExtensionMetricsRegistry interface {
}
// NewManager will initialize a new manager.
func NewManager(log *log.Entry, sg SettingsGetter, ag ApplicationGetter, pg ProjectGetter, rbac RbacEnforcer, ug UserGetter) *Manager {
func NewManager(log *log.Entry, namespace string, sg SettingsGetter, ag ApplicationGetter, pg ProjectGetter, rbac RbacEnforcer, ug UserGetter) *Manager {
return &Manager{
log: log,
namespace: namespace,
settings: sg,
application: ag,
project: pg,
@@ -740,7 +748,7 @@ func (m *Manager) CallExtension() func(http.ResponseWriter, *http.Request) {
user := m.userGetter.GetUser(r.Context())
groups := m.userGetter.GetGroups(r.Context())
prepareRequest(r, extName, app, user, groups)
prepareRequest(r, m.namespace, extName, app, user, groups)
m.log.Debugf("proxing request for extension %q", extName)
// httpsnoop package is used to properly wrap the responseWriter
// and avoid optional intefaces issue:
@@ -763,11 +771,13 @@ func registerMetrics(extName string, metrics httpsnoop.Metrics, extensionMetrics
// the Argo CD extension API section from it. It provides additional information to
// the backend service appending them in the outgoing request headers. The appended
// headers are:
// - Control plane namespace
// - Cluster destination name
// - Cluster destination server
// - Argo CD authenticated username
func prepareRequest(r *http.Request, extName string, app *v1alpha1.Application, username string, groups []string) {
func prepareRequest(r *http.Request, namespace string, extName string, app *v1alpha1.Application, username string, groups []string) {
r.URL.Path = strings.TrimPrefix(r.URL.Path, fmt.Sprintf("%s/%s", URLPrefix, extName))
r.Header.Set(HeaderArgoCDNamespace, namespace)
if app.Spec.Destination.Name != "" {
r.Header.Set(HeaderArgoCDTargetClusterName, app.Spec.Destination.Name)
}

View File

@@ -150,7 +150,7 @@ func TestRegisterExtensions(t *testing.T) {
logger, _ := test.NewNullLogger()
logEntry := logger.WithContext(context.Background())
m := extension.NewManager(logEntry, settMock, nil, nil, nil, nil)
m := extension.NewManager(logEntry, "", settMock, nil, nil, nil, nil)
return &fixture{
settingsGetterMock: settMock,
@@ -248,6 +248,7 @@ func TestCallExtension(t *testing.T) {
userMock *mocks.UserGetter
manager *extension.Manager
}
defaultServerNamespace := "control-plane-ns"
defaultProjectName := "project-name"
setup := func() *fixture {
@@ -260,7 +261,7 @@ func TestCallExtension(t *testing.T) {
logger, _ := test.NewNullLogger()
logEntry := logger.WithContext(context.Background())
m := extension.NewManager(logEntry, settMock, appMock, projMock, rbacMock, userMock)
m := extension.NewManager(logEntry, defaultServerNamespace, settMock, appMock, projMock, rbacMock, userMock)
m.AddMetricsRegistry(metricsMock)
mux := http.NewServeMux()
@@ -444,6 +445,7 @@ func TestCallExtension(t *testing.T) {
require.NoError(t, err)
actual := strings.TrimSuffix(string(body), "\n")
assert.Equal(t, backendResponse, actual)
assert.Equal(t, defaultServerNamespace, resp.Header.Get(extension.HeaderArgoCDNamespace))
assert.Equal(t, clusterURL, resp.Header.Get(extension.HeaderArgoCDTargetClusterURL))
assert.Equal(t, "Bearer some-bearer-token", resp.Header.Get("Authorization"))
assert.Equal(t, "some-user", resp.Header.Get(extension.HeaderArgoCDUsername))

View File

@@ -327,7 +327,7 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts, appsetOpts Applicatio
ag := extension.NewDefaultApplicationGetter(appLister)
pg := extension.NewDefaultProjectGetter(projLister, dbInstance)
ug := extension.NewDefaultUserGetter(policyEnf)
em := extension.NewManager(logger, sg, ag, pg, enf, ug)
em := extension.NewManager(logger, opts.Namespace, sg, ag, pg, enf, ug)
a := &ArgoCDServer{
ArgoCDServerOpts: opts,

View File

@@ -42,6 +42,31 @@ func (c *Consequences) Expect(e Expectation) *Consequences {
return c
}
// ExpectConsistently will continuously evaluate a condition, and it must be true each time it is evaluated, otherwise the test is failed. The condition will be repeatedly evaluated until 'expirationDuration' is met, waiting 'waitDuration' after each success.
func (c *Consequences) ExpectConsistently(e Expectation, waitDuration time.Duration, expirationDuration time.Duration) *Consequences {
// this invocation makes sure this func is not reported as the cause of the failure - we are a "test helper"
c.context.t.Helper()
expiration := time.Now().Add(expirationDuration)
for time.Now().Before(expiration) {
state, message := e(c)
switch state {
case succeeded:
log.Infof("expectation succeeded: %s", message)
case failed:
c.context.t.Fatalf("failed expectation: %s", message)
return c
}
// On condition success: wait, then retry
log.Infof("Expectation '%s' passes, repeating to ensure consistency", message)
time.Sleep(waitDuration)
}
// If the condition never failed before expiring, it is a pass.
return c
}
func (c *Consequences) And(block func(app *Application)) *Consequences {
c.context.t.Helper()
block(c.app())

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