Repository: argoproj/argo-cd
Pull request #9826 (2022-06-29 14:53:44)

chore: upgrade parse-url to avoid SNYK-JS-PARSEURL-2936249
https://security.snyk.io/vuln/SNYK-JS-PARSEURL-2936249


Patch:
diff --git a/USERS.md b/USERS.md
index d2db5516c..08c7ee481 100644
--- a/USERS.md
+++ b/USERS.md
@@ -37,6 +37,7 @@ Currently, the following organizations are **officially** using Argo CD:
 1. [Chargetrip](https://chargetrip.com)
 1. [Chime](https://www.chime.com)
 1. [Cisco ET&I](https://eti.cisco.com/)
+1. [Cobalt](https://www.cobalt.io/)
 1. [Codefresh](https://www.codefresh.io/)
 1. [Codility](https://www.codility.com/)
 1. [Commonbond](https://commonbond.co/)
@@ -211,3 +212,4 @@ Currently, the following organizations are **officially** using Argo CD:
 1. [Trendyol](https://www.trendyol.com/)
 1. [RapidAPI](https://www.rapidapi.com/)
 1. [Pismo](https://pismo.io/)
+1. [South China Morning Post (SCMP)](https://www.scmp.com/)
\ No newline at end of file
diff --git a/applicationset/generators/pull_request.go b/applicationset/generators/pull_request.go
index 2091af4cc..fd38c25b1 100644
--- a/applicationset/generators/pull_request.go
+++ b/applicationset/generators/pull_request.go
@@ -80,12 +80,19 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
 		"_": "-",
 	}
 
+	var shortSHALength int
 	for _, pull := range pulls {
+		shortSHALength = 8
+		if len(pull.HeadSHA) < 8 {
+			shortSHALength = len(pull.HeadSHA)
+		}
+
 		params = append(params, map[string]string{
-			"number":      strconv.Itoa(pull.Number),
-			"branch":      pull.Branch,
-			"branch_slug": slug.Make(pull.Branch),
-			"head_sha":    pull.HeadSHA,
+			"number":         strconv.Itoa(pull.Number),
+			"branch":         pull.Branch,
+			"branch_slug":    slug.Make(pull.Branch),
+			"head_sha":       pull.HeadSHA,
+			"head_short_sha": pull.HeadSHA[:shortSHALength],
 		})
 	}
 	return params, nil
diff --git a/applicationset/generators/scm_provider.go b/applicationset/generators/scm_provider.go
index 17abde67c..bd7b7a6ad 100644
--- a/applicationset/generators/scm_provider.go
+++ b/applicationset/generators/scm_provider.go
@@ -120,13 +120,20 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha
 		return nil, fmt.Errorf("error listing repos: %v", err)
 	}
 	params := make([]map[string]string, 0, len(repos))
+	var shortSHALength int
 	for _, repo := range repos {
+		shortSHALength = 8
+		if len(repo.SHA) < 8 {
+			shortSHALength = len(repo.SHA)
+		}
+
 		params = append(params, map[string]string{
 			"organization":     repo.Organization,
 			"repository":       repo.Repository,
 			"url":              repo.URL,
 			"branch":           repo.Branch,
 			"sha":              repo.SHA,
+			"short_sha":        repo.SHA[:shortSHALength],
 			"labels":           strings.Join(repo.Labels, ","),
 			"branchNormalized": sanitizeName(repo.Branch),
 		})
diff --git a/cmd/argocd-repo-server/commands/argocd_repo_server.go b/cmd/argocd-repo-server/commands/argocd_repo_server.go
index 3644151dc..02ba3af4c 100644
--- a/cmd/argocd-repo-server/commands/argocd_repo_server.go
+++ b/cmd/argocd-repo-server/commands/argocd_repo_server.go
@@ -81,6 +81,7 @@ func NewCommand() *cobra.Command {
 		redisClient                       *redis.Client
 		disableTLS                        bool
 		maxCombinedDirectoryManifestsSize string
+		cmpTarExcludedGlobs               []string
 	)
 	var command = cobra.Command{
 		Use:               cliName,
@@ -121,6 +122,7 @@ func NewCommand() *cobra.Command {
 				PauseGenerationOnFailureForRequests:          getPauseGenerationOnFailureForRequests(),
 				SubmoduleEnabled:                             getSubmoduleEnabled(),
 				MaxCombinedDirectoryManifestsSize:            maxCombinedDirectoryManifestsQuantity,
+				CMPTarExcludedGlobs:                          cmpTarExcludedGlobs,
 			}, askPassServer)
 			errors.CheckError(err)
 
@@ -197,6 +199,7 @@ func NewCommand() *cobra.Command {
 	command.Flags().StringVar(&otlpAddress, "otlp-address", env.StringFromEnv("ARGOCD_REPO_SERVER_OTLP_ADDRESS", ""), "OpenTelemetry collector address to send traces to")
 	command.Flags().BoolVar(&disableTLS, "disable-tls", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_DISABLE_TLS", false), "Disable TLS on the gRPC endpoint")
 	command.Flags().StringVar(&maxCombinedDirectoryManifestsSize, "max-combined-directory-manifests-size", env.StringFromEnv("ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE", "10M"), "Max combined size of manifest files in a directory-type Application")
+	command.Flags().StringArrayVar(&cmpTarExcludedGlobs, "plugin-tar-exclude", env.StringsFromEnv("ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS", []string{}, ";"), "Globs to filter when sending tarballs to plugins.")
 
 	tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command)
 	cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
diff --git a/controller/cache/cache.go b/controller/cache/cache.go
index 4149cc09c..4cae8a361 100644
--- a/controller/cache/cache.go
+++ b/controller/cache/cache.go
@@ -354,7 +354,8 @@ func isTransientNetworkErr(err error) bool {
 	}
 	if strings.Contains(errorString, "net/http: TLS handshake timeout") ||
 		strings.Contains(errorString, "i/o timeout") ||
-		strings.Contains(errorString, "connection timed out") {
+		strings.Contains(errorString, "connection timed out") ||
+		strings.Contains(errorString, "connection reset by peer") {
 		return true
 	}
 	return false
diff --git a/docs/cli_installation.md b/docs/cli_installation.md
index 931cd3f0c..695120276 100644
--- a/docs/cli_installation.md
+++ b/docs/cli_installation.md
@@ -4,10 +4,10 @@ You can download the latest Argo CD version from [the latest release page of thi
 
 ## Linux and WSL
 
-### ArchLinux User Repository ([AUR](https://aur.archlinux.org/packages/))
+### ArchLinux
 
 ```bash
-yay -Sy argocd-bin
+pacman -S argocd
 ```
 
 ### Homebrew
diff --git a/docs/developer-guide/release-process-and-cadence.md b/docs/developer-guide/release-process-and-cadence.md
index fd654e1a5..5e495c7fe 100644
--- a/docs/developer-guide/release-process-and-cadence.md
+++ b/docs/developer-guide/release-process-and-cadence.md
@@ -4,7 +4,7 @@ Argo CD is being developed using the following process:
 
 * Maintainers commit to work on set of features and enhancements and create GitHub milestone to track the work.
 * We are trying to avoid delaying release and prefer moving the feature into the next release if we cannot complete it on time.
-* The new release is published every **3 month**.
+* The new release is published every **3 months**.
 * Critical bug-fixes are cherry-picked into the release branch and delivered using patch releases as frequently as needed.
 
 ## Release Planning
diff --git a/docs/operator-manual/applicationset/Generators-Pull-Request.md b/docs/operator-manual/applicationset/Generators-Pull-Request.md
index 24b68850f..6b1bdf738 100644
--- a/docs/operator-manual/applicationset/Generators-Pull-Request.md
+++ b/docs/operator-manual/applicationset/Generators-Pull-Request.md
@@ -16,9 +16,9 @@ spec:
 ```
 
 !!! note
-    Know the security implications of PR generators in ApplicationSets. 
+    Know the security implications of PR generators in ApplicationSets.
     [Only admins may create ApplicationSets](./Security.md#only-admins-may-createupdatedelete-applicationsets) to avoid
-    leaking Secrets, and [only admins may create PRs](./Security.md#templated-project-field) if the `project` field of 
+    leaking Secrets, and [only admins may create PRs](./Security.md#templated-project-field) if the `project` field of
     an ApplicationSet with a PR generator is templated, to avoid granting management of out-of-bounds resources.
 
 ## GitHub
@@ -82,7 +82,7 @@ spec:
         # Labels is used to filter the MRs that you want to target. (optional)
         labels:
         - preview
-        # MR state is used to filter MRs only with a certain state. (optional) 
+        # MR state is used to filter MRs only with a certain state. (optional)
         pullRequestState: opened
   requeueAfterSeconds: 1800
   template:
@@ -263,8 +263,9 @@ spec:
 
 * `number`: The ID number of the pull request.
 * `branch`: The name of the branch of the pull request head.
-* `branch_slug`: The branch name will be cleaned to be conform to the DNS label standard as defined in [RFC 1123](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names), and truncated to 50 characters to give room to append/suffix-ing it with 13 more characters. 
+* `branch_slug`: The branch name will be cleaned to be conform to the DNS label standard as defined in [RFC 1123](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names), and truncated to 50 characters to give room to append/suffix-ing it with 13 more characters.
 * `head_sha`: This is the SHA of the head of the pull request.
+* `head_short_sha`: This is the short SHA of the head of the pull request (8 characters long or the length of the head SHA if it's shorter).
 
 ## Webhook Configuration
 
diff --git a/docs/operator-manual/applicationset/Generators-SCM-Provider.md b/docs/operator-manual/applicationset/Generators-SCM-Provider.md
index e1a012dc6..2b97fe6fc 100644
--- a/docs/operator-manual/applicationset/Generators-SCM-Provider.md
+++ b/docs/operator-manual/applicationset/Generators-SCM-Provider.md
@@ -20,9 +20,9 @@ spec:
 * `cloneProtocol`: Which protocol to use for the SCM URL. Default is provider-specific but ssh if possible. Not all providers necessarily support all protocols, see provider documentation below for available options.
 
 !!! note
-    Know the security implications of using SCM generators. [Only admins may create ApplicationSets](./Security.md#only-admins-may-createupdatedelete-applicationsets) 
-    to avoid leaking Secrets, and [only admins may create repos/branches](./Security.md#templated-project-field) if the 
-    `project` field of an ApplicationSet with an SCM generator is templated, to avoid granting management of 
+    Know the security implications of using SCM generators. [Only admins may create ApplicationSets](./Security.md#only-admins-may-createupdatedelete-applicationsets)
+    to avoid leaking Secrets, and [only admins may create repos/branches](./Security.md#templated-project-field) if the
+    `project` field of an ApplicationSet with an SCM generator is templated, to avoid granting management of
     out-of-bounds resources.
 
 ## GitHub
@@ -180,7 +180,7 @@ Available clone protocols are `ssh` and `https`.
 
 ## Azure DevOps
 
-Uses the Azure DevOps API to look up eligible repositories based on a team project within an Azure DevOps organization. 
+Uses the Azure DevOps API to look up eligible repositories based on a team project within an Azure DevOps organization.
 The default Azure DevOps URL is `https://dev.azure.com`, but this can be overridden with the field `azureDevOps.api`.
 
 ```yaml
@@ -277,6 +277,7 @@ spec:
 * `repository`: The name of the repository.
 * `url`: The clone URL for the repository.
 * `branch`: The default branch of the repository.
-* `sha`: The Git commit SHA for the branch
-* `labels`: A comma-separated list of repository labels
+* `sha`: The Git commit SHA for the branch.
+* `short_sha`: The abbreviated Git commit SHA for the branch (8 chars or the length of the `sha` if it's shorter).
+* `labels`: A comma-separated list of repository labels.
 * `branchNormalized`: The value of `branch` normalized to contain only lowercase alphanumeric characters, '-' or '.'.
diff --git a/docs/operator-manual/argocd-cmd-params-cm.yaml b/docs/operator-manual/argocd-cmd-params-cm.yaml
index 5cf37748f..52c45cff3 100644
--- a/docs/operator-manual/argocd-cmd-params-cm.yaml
+++ b/docs/operator-manual/argocd-cmd-params-cm.yaml
@@ -111,3 +111,5 @@ data:
   # for 300x memory expansion and N Applications running at the same time.
   # (example 10M max * 300 expansion * 10 Apps = 30G max theoretical memory usage).
   reposerver.max.combined.directory.manifests.size: '10M'
+  # Paths to be excluded from the tarball streamed to plugins. Separate with ;
+  reposerver.plugin.tar.exclusions: ""
diff --git a/docs/operator-manual/server-commands/argocd-repo-server.md b/docs/operator-manual/server-commands/argocd-repo-server.md
index 95b945e05..fe4b0c7a7 100644
--- a/docs/operator-manual/server-commands/argocd-repo-server.md
+++ b/docs/operator-manual/server-commands/argocd-repo-server.md
@@ -22,6 +22,7 @@ argocd-repo-server [flags]
       --metrics-port int                               Start metrics server on given port (default 8084)
       --otlp-address string                            OpenTelemetry collector address to send traces to
       --parallelismlimit int                           Limit on number of concurrent manifests generate requests. Any value less the 1 means no limit.
+      --plugin-tar-exclude stringArray                 Globs to filter when sending tarballs to plugins.
       --port int                                       Listen on given port for incoming connections (default 8081)
       --redis string                                   Redis server hostname and port (e.g. argocd-redis:6379). 
       --redis-ca-certificate string                    Path to Redis server CA certificate (e.g. /etc/certs/redis/ca.crt). If not specified, system trusted CAs will be used for server certificate validation.
diff --git a/docs/user-guide/config-management-plugins.md b/docs/user-guide/config-management-plugins.md
index 06d4cbc64..f50646272 100644
--- a/docs/user-guide/config-management-plugins.md
+++ b/docs/user-guide/config-management-plugins.md
@@ -234,3 +234,17 @@ If you don't need to set any environment variables, you can set an empty plugin
     Each CMP command will also independently timeout on the `ARGOCD_EXEC_TIMEOUT` set for the CMP sidecar. The default
     is 90s. So if you increase the repo server timeout greater than 90s, be sure to set `ARGOCD_EXEC_TIMEOUT` on the
     sidecar.
+
+## Tarball stream filtering
+
+In order to increase the speed of manifest generation, certain files and folders can be excluded from being sent to your
+plugin. We recommend excluding your `.git` folder if it isn't necessary. Use Go's 
+[filepatch.Match](https://pkg.go.dev/path/filepath#Match) syntax.
+
+You can set it one of three ways:
+1. The `--plugin-tar-exclude` argument on the repo server.
+2. The `reposerver.plugin.tar.exclusions` key if you are using `argocd-cmd-params-cm`
+3. Directly setting 'ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS' environment variable on the repo server.
+
+For option 1, the flag can be repeated multiple times. For option 2 and 3, you can specify multiple globs by separating
+them with semicolons.
\ No newline at end of file
diff --git a/manifests/base/repo-server/argocd-repo-server-deployment.yaml b/manifests/base/repo-server/argocd-repo-server-deployment.yaml
index 252bc36e6..72e448455 100644
--- a/manifests/base/repo-server/argocd-repo-server-deployment.yaml
+++ b/manifests/base/repo-server/argocd-repo-server-deployment.yaml
@@ -107,6 +107,12 @@ spec:
                 name: argocd-cmd-params-cm
                 key: reposerver.max.combined.directory.manifests.size
                 optional: true
+          - name: ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS
+            valueFrom:
+              configMapKeyRef:
+                name: argocd-cmd-params-cm
+                key: reposerver.plugin.tar.exclusions
+                optional: true
           - name: HELM_CACHE_HOME
             value: /helm-working-dir
           - name: HELM_CONFIG_HOME
diff --git a/manifests/core-install.yaml b/manifests/core-install.yaml
index b8570a7aa..00a32c751 100644
--- a/manifests/core-install.yaml
+++ b/manifests/core-install.yaml
@@ -9757,6 +9757,12 @@ spec:
               key: reposerver.max.combined.directory.manifests.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.plugin.tar.exclusions
+              name: argocd-cmd-params-cm
+              optional: true
         - name: HELM_CACHE_HOME
           value: /helm-working-dir
         - name: HELM_CONFIG_HOME
diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml
index 0119c9123..d03bc0cd7 100644
--- a/manifests/ha/install.yaml
+++ b/manifests/ha/install.yaml
@@ -10864,6 +10864,12 @@ spec:
               key: reposerver.max.combined.directory.manifests.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.plugin.tar.exclusions
+              name: argocd-cmd-params-cm
+              optional: true
         - name: HELM_CACHE_HOME
           value: /helm-working-dir
         - name: HELM_CONFIG_HOME
diff --git a/manifests/ha/namespace-install.yaml b/manifests/ha/namespace-install.yaml
index 6747aabcb..9f1159cf0 100644
--- a/manifests/ha/namespace-install.yaml
+++ b/manifests/ha/namespace-install.yaml
@@ -1638,6 +1638,12 @@ spec:
               key: reposerver.max.combined.directory.manifests.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.plugin.tar.exclusions
+              name: argocd-cmd-params-cm
+              optional: true
         - name: HELM_CACHE_HOME
           value: /helm-working-dir
         - name: HELM_CONFIG_HOME
diff --git a/manifests/install.yaml b/manifests/install.yaml
index 2a8e182e0..c796f1fe5 100644
--- a/manifests/install.yaml
+++ b/manifests/install.yaml
@@ -10206,6 +10206,12 @@ spec:
               key: reposerver.max.combined.directory.manifests.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.plugin.tar.exclusions
+              name: argocd-cmd-params-cm
+              optional: true
         - name: HELM_CACHE_HOME
           value: /helm-working-dir
         - name: HELM_CONFIG_HOME
diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml
index 5c39145ba..a351e12c8 100644
--- a/manifests/namespace-install.yaml
+++ b/manifests/namespace-install.yaml
@@ -980,6 +980,12 @@ spec:
               key: reposerver.max.combined.directory.manifests.size
               name: argocd-cmd-params-cm
               optional: true
+        - name: ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS
+          valueFrom:
+            configMapKeyRef:
+              key: reposerver.plugin.tar.exclusions
+              name: argocd-cmd-params-cm
+              optional: true
         - name: HELM_CACHE_HOME
           value: /helm-working-dir
         - name: HELM_CONFIG_HOME
diff --git a/pkg/apis/application/v1alpha1/types.go b/pkg/apis/application/v1alpha1/types.go
index 29e0c565e..e8860128f 100644
--- a/pkg/apis/application/v1alpha1/types.go
+++ b/pkg/apis/application/v1alpha1/types.go
@@ -1542,6 +1542,19 @@ func isValidAction(action string) bool {
 	return false
 }
 
+// TODO: same as validActions, refacotor to use rbacpolicy.ResourceApplications etc.
+var validResources = map[string]bool{
+	"applications": true,
+	"repositories": true,
+	"clusters":     true,
+	"exec":         true,
+	"logs":         true,
+}
+
+func isValidResource(resource string) bool {
+	return validResources[resource]
+}
+
 func validatePolicy(proj string, role string, policy string) error {
 	policyComponents := strings.Split(policy, ",")
 	if len(policyComponents) != 6 || strings.Trim(policyComponents[0], " ") != "p" {
@@ -1555,7 +1568,7 @@ func validatePolicy(proj string, role string, policy string) error {
 	}
 	// resource
 	resource := strings.Trim(policyComponents[2], " ")
-	if resource != "applications" && resource != "repositories" && resource != "clusters" {
+	if !isValidResource(resource) {
 		return status.Errorf(codes.InvalidArgument, "invalid policy rule '%s': project resource must be: 'applications', 'repositories' or 'clusters', not '%s'", policy, resource)
 	}
 	// action
diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go
index cdfb675d6..27d123413 100644
--- a/reposerver/repository/repository.go
+++ b/reposerver/repository/repository.go
@@ -103,6 +103,7 @@ type RepoServerInitConstants struct {
 	PauseGenerationOnFailureForRequests          int
 	SubmoduleEnabled                             bool
 	MaxCombinedDirectoryManifestsSize            resource.Quantity
+	CMPTarExcludedGlobs                          []string
 }
 
 // NewService returns a new instance of the Manifest service
@@ -213,7 +214,7 @@ func (s *Service) ListApps(ctx context.Context, q *apiclient.ListAppsRequest) (*
 	}
 
 	defer io.Close(closer)
-	apps, err := discovery.Discover(ctx, gitClient.Root(), q.EnabledSourceTypes)
+	apps, err := discovery.Discover(ctx, gitClient.Root(), q.EnabledSourceTypes, s.initConstants.CMPTarExcludedGlobs)
 	if err != nil {
 		return nil, err
 	}
@@ -465,7 +466,7 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA,
 	var manifestGenResult *apiclient.ManifestResponse
 	opContext, err := opContextSrc()
 	if err == nil {
-		manifestGenResult, err = GenerateManifests(ctx, opContext.appPath, repoRoot, commitSHA, q, false, s.gitCredsStore, s.initConstants.MaxCombinedDirectoryManifestsSize, WithCMPTarDoneChannel(ch.tarDoneCh))
+		manifestGenResult, err = GenerateManifests(ctx, opContext.appPath, repoRoot, commitSHA, q, false, s.gitCredsStore, s.initConstants.MaxCombinedDirectoryManifestsSize, WithCMPTarDoneChannel(ch.tarDoneCh), WithCMPTarExcludedGlobs(s.initConstants.CMPTarExcludedGlobs))
 	}
 	if err != nil {
 		// If manifest generation error caching is enabled
@@ -872,7 +873,8 @@ func getRepoCredential(repoCredentials []*v1alpha1.RepoCreds, repoURL string) *v
 
 type GenerateManifestOpt func(*generateManifestOpt)
 type generateManifestOpt struct {
-	cmpTarDoneCh chan<- bool
+	cmpTarDoneCh        chan<- bool
+	cmpTarExcludedGlobs []string
 }
 
 func newGenerateManifestOpt(opts ...GenerateManifestOpt) *generateManifestOpt {
@@ -892,6 +894,14 @@ func WithCMPTarDoneChannel(ch chan<- bool) GenerateManifestOpt {
 	}
 }
 
+// WithCMPTarExcludedGlobs defines globs for files to filter out when streaming the tarball
+// to a CMP sidecar.
+func WithCMPTarExcludedGlobs(excludedGlobs []string) GenerateManifestOpt {
+	return func(o *generateManifestOpt) {
+		o.cmpTarExcludedGlobs = excludedGlobs
+	}
+}
+
 // GenerateManifests generates manifests from a path. Overrides are applied as a side effect on the given ApplicationSource.
 func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, q *apiclient.ManifestRequest, isLocal bool, gitCredsStore git.CredsStore, maxCombinedManifestQuantity resource.Quantity, opts ...GenerateManifestOpt) (*apiclient.ManifestResponse, error) {
 	opt := newGenerateManifestOpt(opts...)
@@ -900,7 +910,7 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string,
 
 	resourceTracking := argo.NewResourceTracking()
 
-	appSourceType, err := GetAppSourceType(ctx, q.ApplicationSource, appPath, q.AppName, q.EnabledSourceTypes)
+	appSourceType, err := GetAppSourceType(ctx, q.ApplicationSource, appPath, q.AppName, q.EnabledSourceTypes, opt.cmpTarExcludedGlobs)
 	if err != nil {
 		return nil, err
 	}
@@ -924,7 +934,7 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string,
 		if q.ApplicationSource.Plugin != nil && q.ApplicationSource.Plugin.Name != "" {
 			targetObjs, err = runConfigManagementPlugin(appPath, repoRoot, env, q, q.Repo.GetGitCreds(gitCredsStore))
 		} else {
-			targetObjs, err = runConfigManagementPluginSidecars(ctx, appPath, repoRoot, env, q, q.Repo.GetGitCreds(gitCredsStore), opt.cmpTarDoneCh)
+			targetObjs, err = runConfigManagementPluginSidecars(ctx, appPath, repoRoot, env, q, q.Repo.GetGitCreds(gitCredsStore), opt.cmpTarDoneCh, opt.cmpTarExcludedGlobs)
 			if err != nil {
 				err = fmt.Errorf("plugin sidecar failed. %s", err.Error())
 			}
@@ -1058,7 +1068,7 @@ func mergeSourceParameters(source *v1alpha1.ApplicationSource, path, appName str
 }
 
 // GetAppSourceType returns explicit application source type or examines a directory and determines its application source type
-func GetAppSourceType(ctx context.Context, source *v1alpha1.ApplicationSource, path, appName string, enableGenerateManifests map[string]bool) (v1alpha1.ApplicationSourceType, error) {
+func GetAppSourceType(ctx context.Context, source *v1alpha1.ApplicationSource, path, appName string, enableGenerateManifests map[string]bool, tarExcludedGlobs []string) (v1alpha1.ApplicationSourceType, error) {
 	err := mergeSourceParameters(source, path, appName)
 	if err != nil {
 		return "", fmt.Errorf("error while parsing source parameters: %v", err)
@@ -1075,7 +1085,7 @@ func GetAppSourceType(ctx context.Context, source *v1alpha1.ApplicationSource, p
 		}
 		return *appSourceType, nil
 	}
-	appType, err := discovery.AppType(ctx, path, enableGenerateManifests)
+	appType, err := discovery.AppType(ctx, path, enableGenerateManifests, tarExcludedGlobs)
 	if err != nil {
 		return "", err
 	}
@@ -1479,7 +1489,7 @@ func getPluginEnvs(envVars *v1alpha1.Env, q *apiclient.ManifestRequest, creds gi
 	return env, nil
 }
 
-func runConfigManagementPluginSidecars(ctx context.Context, appPath, repoPath string, envVars *v1alpha1.Env, q *apiclient.ManifestRequest, creds git.Creds, tarDoneCh chan<- bool) ([]*unstructured.Unstructured, error) {
+func runConfigManagementPluginSidecars(ctx context.Context, appPath, repoPath string, envVars *v1alpha1.Env, q *apiclient.ManifestRequest, creds git.Creds, tarDoneCh chan<- bool, tarExcludedGlobs []string) ([]*unstructured.Unstructured, error) {
 	// compute variables.
 	env, err := getPluginEnvs(envVars, q, creds, true)
 	if err != nil {
@@ -1487,14 +1497,14 @@ func runConfigManagementPluginSidecars(ctx context.Context, appPath, repoPath st
 	}
 
 	// detect config management plugin server (sidecar)
-	conn, cmpClient, err := discovery.DetectConfigManagementPlugin(ctx, appPath, env)
+	conn, cmpClient, err := discovery.DetectConfigManagementPlugin(ctx, appPath, env, tarExcludedGlobs)
 	if err != nil {
 		return nil, err
 	}
 	defer io.Close(conn)
 
 	// generate manifests using commands provided in plugin config file in detected cmp-server sidecar
-	cmpManifests, err := generateManifestsCMP(ctx, appPath, repoPath, env, cmpClient, tarDoneCh)
+	cmpManifests, err := generateManifestsCMP(ctx, appPath, repoPath, env, cmpClient, tarDoneCh, tarExcludedGlobs)
 	if err != nil {
 		return nil, fmt.Errorf("error generating manifests in cmp: %s", err)
 	}
@@ -1512,7 +1522,7 @@ func runConfigManagementPluginSidecars(ctx context.Context, appPath, repoPath st
 // generateManifestsCMP will send the appPath files to the cmp-server over a gRPC stream.
 // The cmp-server will generate the manifests. Returns a response object with the generated
 // manifests.
-func generateManifestsCMP(ctx context.Context, appPath, repoPath string, env []string, cmpClient pluginclient.ConfigManagementPluginServiceClient, tarDoneCh chan<- bool) (*pluginclient.ManifestResponse, error) {
+func generateManifestsCMP(ctx context.Context, appPath, repoPath string, env []string, cmpClient pluginclient.ConfigManagementPluginServiceClient, tarDoneCh chan<- bool, tarExcludedGlobs []string) (*pluginclient.ManifestResponse, error) {
 	generateManifestStream, err := cmpClient.GenerateManifest(ctx, grpc_retry.Disable())
 	if err != nil {
 		return nil, fmt.Errorf("error getting generateManifestStream: %s", err)
@@ -1520,7 +1530,7 @@ func generateManifestsCMP(ctx context.Context, appPath, repoPath string, env []s
 	opts := []cmp.SenderOption{
 		cmp.WithTarDoneChan(tarDoneCh),
 	}
-	err = cmp.SendRepoStream(generateManifestStream.Context(), appPath, repoPath, generateManifestStream, env, opts...)
+	err = cmp.SendRepoStream(generateManifestStream.Context(), appPath, repoPath, generateManifestStream, env, tarExcludedGlobs, opts...)
 	if err != nil {
 		return nil, fmt.Errorf("error sending file to cmp-server: %s", err)
 	}
@@ -1538,7 +1548,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD
 			return err
 		}
 
-		appSourceType, err := GetAppSourceType(ctx, q.Source, opContext.appPath, q.AppName, q.EnabledSourceTypes)
+		appSourceType, err := GetAppSourceType(ctx, q.Source, opContext.appPath, q.AppName, q.EnabledSourceTypes, s.initConstants.CMPTarExcludedGlobs)
 		if err != nil {
 			return err
 		}
@@ -1653,7 +1663,7 @@ func loadFileIntoIfExists(path pathutil.ResolvedFilePath, destination *string) e
 	info, err := os.Stat(stringPath)
 
 	if err == nil && !info.IsDir() {
-		bytes, err := ioutil.ReadFile(stringPath);
+		bytes, err := ioutil.ReadFile(stringPath)
 		if err != nil {
 			return err
 		}
diff --git a/ui/yarn.lock b/ui/yarn.lock
index ab0301af3..cd62427a4 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -6984,10 +6984,10 @@ parse-json@^5.2.0:
     json-parse-even-better-errors "^2.3.0"
     lines-and-columns "^1.1.6"
 
-parse-path@^4.0.0:
-  version "4.0.3"
-  resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.3.tgz#82d81ec3e071dcc4ab49aa9f2c9c0b8966bb22bf"
-  integrity sha512-9Cepbp2asKnWTJ9x2kpw6Fe8y9JDbqwahGCTvklzd/cEq5C5JC59x2Xb0Kx+x0QZ8bvNquGO8/BWP0cwBHzSAA==
+parse-path@^4.0.4:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.4.tgz#4bf424e6b743fb080831f03b536af9fc43f0ffea"
+  integrity sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==
   dependencies:
     is-ssh "^1.3.0"
     protocols "^1.4.0"
@@ -6995,13 +6995,13 @@ parse-path@^4.0.0:
     query-string "^6.13.8"
 
 parse-url@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.0.tgz#f5dd262a7de9ec00914939220410b66cff09107d"
-  integrity sha512-cYyojeX7yIIwuJzledIHeLUBVJ6COVLeT4eF+2P6aKVzwvgKQPndCBv3+yQ7pcWjqToYwaligxzSYNNmGoMAvw==
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.2.tgz#4a30b057bfc452af64512dfb1a7755c103db3ea1"
+  integrity sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==
   dependencies:
     is-ssh "^1.3.0"
     normalize-url "^6.1.0"
-    parse-path "^4.0.0"
+    parse-path "^4.0.4"
     protocols "^1.4.0"
 
 parse5@6.0.1:
diff --git a/util/app/discovery/discovery.go b/util/app/discovery/discovery.go
index bda4f942a..c4fb0d905 100644
--- a/util/app/discovery/discovery.go
+++ b/util/app/discovery/discovery.go
@@ -29,11 +29,11 @@ func IsManifestGenerationEnabled(sourceType v1alpha1.ApplicationSourceType, enab
 	return enabled
 }
 
-func Discover(ctx context.Context, repoPath string, enableGenerateManifests map[string]bool) (map[string]string, error) {
+func Discover(ctx context.Context, repoPath string, enableGenerateManifests map[string]bool, tarExcludedGlobs []string) (map[string]string, error) {
 	apps := make(map[string]string)
 
 	// Check if it is CMP
-	conn, _, err := DetectConfigManagementPlugin(ctx, repoPath, []string{})
+	conn, _, err := DetectConfigManagementPlugin(ctx, repoPath, []string{}, tarExcludedGlobs)
 	if err == nil {
 		// Found CMP
 		io.Close(conn)
@@ -65,8 +65,8 @@ func Discover(ctx context.Context, repoPath string, enableGenerateManifests map[
 	return apps, err
 }
 
-func AppType(ctx context.Context, path string, enableGenerateManifests map[string]bool) (string, error) {
-	apps, err := Discover(ctx, path, enableGenerateManifests)
+func AppType(ctx context.Context, path string, enableGenerateManifests map[string]bool, tarExcludedGlobs []string) (string, error) {
+	apps, err := Discover(ctx, path, enableGenerateManifests, tarExcludedGlobs)
 	if err != nil {
 		return "", err
 	}
@@ -82,7 +82,7 @@ func AppType(ctx context.Context, path string, enableGenerateManifests map[strin
 // 3. check isSupported(path)?
 // 4.a if no then close connection
 // 4.b if yes then return conn for detected plugin
-func DetectConfigManagementPlugin(ctx context.Context, repoPath string, env []string) (io.Closer, pluginclient.ConfigManagementPluginServiceClient, error) {
+func DetectConfigManagementPlugin(ctx context.Context, repoPath string, env []string, tarExcludedGlobs []string) (io.Closer, pluginclient.ConfigManagementPluginServiceClient, error) {
 	var conn io.Closer
 	var cmpClient pluginclient.ConfigManagementPluginServiceClient
 
@@ -106,7 +106,7 @@ func DetectConfigManagementPlugin(ctx context.Context, repoPath string, env []st
 				continue
 			}
 
-			isSupported, err := matchRepositoryCMP(ctx, repoPath, cmpClient, env)
+			isSupported, err := matchRepositoryCMP(ctx, repoPath, cmpClient, env, tarExcludedGlobs)
 			if err != nil {
 				log.Errorf("repository %s is not the match because %v", repoPath, err)
 				continue
@@ -131,13 +131,13 @@ func DetectConfigManagementPlugin(ctx context.Context, repoPath string, env []st
 // matchRepositoryCMP will send the repoPath to the cmp-server. The cmp-server will
 // inspect the files and return true if the repo is supported for manifest generation.
 // Will return false otherwise.
-func matchRepositoryCMP(ctx context.Context, repoPath string, client pluginclient.ConfigManagementPluginServiceClient, env []string) (bool, error) {
+func matchRepositoryCMP(ctx context.Context, repoPath string, client pluginclient.ConfigManagementPluginServiceClient, env []string, tarExcludedGlobs []string) (bool, error) {
 	matchRepoStream, err := client.MatchRepository(ctx, grpc_retry.Disable())
 	if err != nil {
 		return false, fmt.Errorf("error getting stream client: %s", err)
 	}
 
-	err = cmp.SendRepoStream(ctx, repoPath, repoPath, matchRepoStream, env)
+	err = cmp.SendRepoStream(ctx, repoPath, repoPath, matchRepoStream, env, tarExcludedGlobs)
 	if err != nil {
 		return false, fmt.Errorf("error sending stream: %s", err)
 	}
diff --git a/util/cmp/stream.go b/util/cmp/stream.go
index 7eb5ff860..ad7b8b053 100644
--- a/util/cmp/stream.go
+++ b/util/cmp/stream.go
@@ -84,11 +84,11 @@ func WithTarDoneChan(ch chan<- bool) SenderOption {
 
 // SendRepoStream will compress the files under the given repoPath and send
 // them using the plugin stream sender.
-func SendRepoStream(ctx context.Context, appPath, repoPath string, sender StreamSender, env []string, opts ...SenderOption) error {
+func SendRepoStream(ctx context.Context, appPath, repoPath string, sender StreamSender, env []string, excludedGlobs []string, opts ...SenderOption) error {
 	opt := newSenderOption(opts...)
 
 	// compress all files in appPath in tgz
-	tgz, checksum, err := compressFiles(repoPath)
+	tgz, checksum, err := compressFiles(repoPath, excludedGlobs)
 	if err != nil {
 		return fmt.Errorf("error compressing repo files: %w", err)
 	}
@@ -162,11 +162,10 @@ func closeAndDelete(f *os.File) {
 }
 
 // compressFiles will create a tgz file with all contents of appPath
-// directory excluding the .git folder. Returns the file alongside
-// its sha256 hash to be used as checksum. It is the responsibility
-// of the caller to close the file.
-func compressFiles(appPath string) (*os.File, string, error) {
-	excluded := []string{".git"}
+// directory excluding globs in the excluded array. Returns the file
+// alongside its sha256 hash to be used as checksum. It is the
+// responsibility of the caller to close the file.
+func compressFiles(appPath string, excluded []string) (*os.File, string, error) {
 	appName := filepath.Base(appPath)
 	tempDir, err := files.CreateTempDir(os.TempDir())
 	if err != nil {
diff --git a/util/env/env.go b/util/env/env.go
index 3c5daeee9..910c4525f 100644
--- a/util/env/env.go
+++ b/util/env/env.go
@@ -126,6 +126,13 @@ func StringFromEnv(env string, defaultValue string) string {
 	return defaultValue
 }
 
+func StringsFromEnv(env string, defaultValue []string, separator string) []string {
+	if str := os.Getenv(env); str != "" {
+		return strings.Split(str, separator)
+	}
+	return defaultValue
+}
+
 // ParseBoolFromEnv retrieves a boolean value from given environment envVar.
 // Returns default value if envVar is not set.
 //


Test patch:
diff --git a/applicationset/generators/pull_request_test.go b/applicationset/generators/pull_request_test.go
index 0e1878fad..4cb18d64b 100644
--- a/applicationset/generators/pull_request_test.go
+++ b/applicationset/generators/pull_request_test.go
@@ -37,10 +37,11 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
 			},
 			expected: []map[string]string{
 				{
-					"number":      "1",
-					"branch":      "branch1",
-					"branch_slug": "branch1",
-					"head_sha":    "089d92cbf9ff857a39e6feccd32798ca700fb958",
+					"number":         "1",
+					"branch":         "branch1",
+					"branch_slug":    "branch1",
+					"head_sha":       "089d92cbf9ff857a39e6feccd32798ca700fb958",
+					"head_short_sha": "089d92cb",
 				},
 			},
 			expectedErr: nil,
@@ -61,10 +62,36 @@ func TestPullRequestGithubGenerateParams(t *testing.T) {
 			},
 			expected: []map[string]string{
 				{
-					"number":      "2",
-					"branch":      "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
-					"branch_slug": "feat-areally-long-pull-request-name-to-test-argo",
-					"head_sha":    "9b34ff5bd418e57d58891eb0aa0728043ca1e8be",
+					"number":         "2",
+					"branch":         "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
+					"branch_slug":    "feat-areally-long-pull-request-name-to-test-argo",
+					"head_sha":       "9b34ff5bd418e57d58891eb0aa0728043ca1e8be",
+					"head_short_sha": "9b34ff5b",
+				},
+			},
+			expectedErr: nil,
+		},
+		{
+			selectFunc: func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
+				return pullrequest.NewFakeService(
+					ctx,
+					[]*pullrequest.PullRequest{
+						&pullrequest.PullRequest{
+							Number:  1,
+							Branch:  "a-very-short-sha",
+							HeadSHA: "abcd",
+						},
+					},
+					nil,
+				)
+			},
+			expected: []map[string]string{
+				{
+					"number":         "1",
+					"branch":         "a-very-short-sha",
+					"branch_slug":    "a-very-short-sha",
+					"head_sha":       "abcd",
+					"head_short_sha": "abcd",
 				},
 			},
 			expectedErr: nil,
diff --git a/applicationset/generators/scm_provider_test.go b/applicationset/generators/scm_provider_test.go
index 94bcec100..de072241c 100644
--- a/applicationset/generators/scm_provider_test.go
+++ b/applicationset/generators/scm_provider_test.go
@@ -87,7 +87,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
 				Repository:   "repo1",
 				URL:          "git@github.com:myorg/repo1.git",
 				Branch:       "main",
-				SHA:          "abcd1234",
+				SHA:          "0bc57212c3cbbec69d20b34c507284bd300def5b",
 				Labels:       []string{"prod", "staging"},
 			},
 			{
@@ -95,7 +95,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
 				Repository:   "repo2",
 				URL:          "git@github.com:myorg/repo2.git",
 				Branch:       "main",
-				SHA:          "00000000",
+				SHA:          "59d0",
 			},
 		},
 	}
@@ -109,7 +109,9 @@ func TestSCMProviderGenerateParams(t *testing.T) {
 	assert.Equal(t, "repo1", params[0]["repository"])
 	assert.Equal(t, "git@github.com:myorg/repo1.git", params[0]["url"])
 	assert.Equal(t, "main", params[0]["branch"])
-	assert.Equal(t, "abcd1234", params[0]["sha"])
+	assert.Equal(t, "0bc57212c3cbbec69d20b34c507284bd300def5b", params[0]["sha"])
+	assert.Equal(t, "0bc57212", params[0]["short_sha"])
+	assert.Equal(t, "59d0", params[1]["short_sha"])
 	assert.Equal(t, "prod,staging", params[0]["labels"])
 	assert.Equal(t, "repo2", params[1]["repository"])
 }
diff --git a/controller/cache/cache_test.go b/controller/cache/cache_test.go
index aa6f26540..dcff97edb 100644
--- a/controller/cache/cache_test.go
+++ b/controller/cache/cache_test.go
@@ -111,6 +111,7 @@ func TestIsRetryableError(t *testing.T) {
 		tlsHandshakeTimeoutErr net.Error = netError("net/http: TLS handshake timeout")
 		ioTimeoutErr           net.Error = netError("i/o timeout")
 		connectionTimedout     net.Error = netError("connection timed out")
+		connectionReset        net.Error = netError("connection reset by peer")
 	)
 	t.Run("Nil", func(t *testing.T) {
 		assert.False(t, isRetryableError(nil))
@@ -148,4 +149,7 @@ func TestIsRetryableError(t *testing.T) {
 	t.Run("ConnectionTimeout", func(t *testing.T) {
 		assert.True(t, isRetryableError(connectionTimedout))
 	})
+	t.Run("ConnectionReset", func(t *testing.T) {
+		assert.True(t, isRetryableError(connectionReset))
+	})
 }
diff --git a/pkg/apis/application/v1alpha1/types_test.go b/pkg/apis/application/v1alpha1/types_test.go
index bfefa2c93..a06facf59 100644
--- a/pkg/apis/application/v1alpha1/types_test.go
+++ b/pkg/apis/application/v1alpha1/types_test.go
@@ -2546,10 +2546,19 @@ func Test_validatePolicy_projIsNotRegex(t *testing.T) {
 }
 
 func Test_validatePolicy_ValidResource(t *testing.T) {
-	err := validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, repositories, *, some-project/*, allow")
+	err := validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, applications, *, some-project/*, allow")
+	assert.NoError(t, err)
+	err = validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, repositories, *, some-project/*, allow")
 	assert.NoError(t, err)
 	err = validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, clusters, *, some-project/*, allow")
 	assert.NoError(t, err)
+	err = validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, exec, *, some-project/*, allow")
+	assert.NoError(t, err)
+	err = validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, logs, *, some-project/*, allow")
+	assert.NoError(t, err)
+	err = validatePolicy("some-project", "org-admin", "p, proj:some-project:org-admin, unknown, *, some-project/*, allow")
+	assert.Error(t, err)
+
 }
 
 func TestEnvsubst(t *testing.T) {
diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go
index 28ac1db2d..a57d15401 100644
--- a/reposerver/repository/repository_test.go
+++ b/reposerver/repository/repository_test.go
@@ -1049,15 +1049,15 @@ func TestGenerateNullList(t *testing.T) {
 }
 
 func TestIdentifyAppSourceTypeByAppDirWithKustomizations(t *testing.T) {
-	sourceType, err := GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/kustomization_yaml", "testapp", map[string]bool{})
+	sourceType, err := GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/kustomization_yaml", "testapp", map[string]bool{}, []string{})
 	assert.Nil(t, err)
 	assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType)
 
-	sourceType, err = GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/kustomization_yml", "testapp", map[string]bool{})
+	sourceType, err = GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/kustomization_yml", "testapp", map[string]bool{}, []string{})
 	assert.Nil(t, err)
 	assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType)
 
-	sourceType, err = GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/Kustomization", "testapp", map[string]bool{})
+	sourceType, err = GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/Kustomization", "testapp", map[string]bool{}, []string{})
 	assert.Nil(t, err)
 	assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType)
 }
@@ -1582,7 +1582,7 @@ func TestGenerateManifestsWithAppParameterFile(t *testing.T) {
 			source := &argoappv1.ApplicationSource{
 				Path: path,
 			}
-			sourceCopy := source.DeepCopy()  // make a copy in case GenerateManifest mutates it.
+			sourceCopy := source.DeepCopy() // make a copy in case GenerateManifest mutates it.
 			_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
 				Repo:              &argoappv1.Repository{},
 				ApplicationSource: sourceCopy,
diff --git a/test/container/Dockerfile b/test/container/Dockerfile
index b4ff7cdcb..a07bc8d84 100644
--- a/test/container/Dockerfile
+++ b/test/container/Dockerfile
@@ -1,5 +1,10 @@
 FROM docker.io/library/redis:7.0.0 as redis
 
+# There are libraries we will want to copy from here in the final stage of the
+# build, but the COPY directive does not have a way to determine system
+# architecture, so we create a symlink here to facilitate copying.
+RUN ln -s /usr/lib/$(uname -m)-linux-gnu /usr/lib/linux-gnu 
+
 FROM docker.io/library/node:12.18.4-buster as node
 
 FROM docker.io/library/golang:1.18 as golang
@@ -66,8 +71,11 @@ COPY --from=redis /usr/local/bin/* /usr/local/bin/
 
 # Copy redis dependencies/shared libraries
 # Ubuntu 22.04+ has moved to OpenSSL3 and no longer provides these libraries
-COPY --from=redis /usr/lib/x86_64-linux-gnu/libssl.so.1.1 /usr/lib/x86_64-linux-gnu/
-COPY --from=redis /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 /usr/lib/x86_64-linux-gnu/
+COPY --from=redis /usr/lib/linux-gnu/libssl.so.1.1 /usr/lib/linux-gnu/
+COPY --from=redis /usr/lib/linux-gnu/libcrypto.so.1.1 /usr/lib/linux-gnu/
+RUN mv /usr/lib/linux-gnu/libssl.so.1.1 /usr/lib/$(uname -m)-linux-gnu/ && \
+    mv /usr/lib/linux-gnu/libcrypto.so.1.1 /usr/lib/$(uname -m)-linux-gnu/ && \
+    rm -rf /usr/lib/linux-gnu/
 
 # Copy registry binaries to the image
 COPY --from=registry /bin/registry /usr/local/bin/
diff --git a/util/app/discovery/discovery_test.go b/util/app/discovery/discovery_test.go
index 3509c2466..d6828aea7 100644
--- a/util/app/discovery/discovery_test.go
+++ b/util/app/discovery/discovery_test.go
@@ -10,7 +10,7 @@ import (
 )
 
 func TestDiscover(t *testing.T) {
-	apps, err := Discover(context.Background(), "./testdata", map[string]bool{})
+	apps, err := Discover(context.Background(), "./testdata", map[string]bool{}, []string{})
 	assert.NoError(t, err)
 	assert.Equal(t, map[string]string{
 		"foo": "Kustomize",
@@ -19,15 +19,15 @@ func TestDiscover(t *testing.T) {
 }
 
 func TestAppType(t *testing.T) {
-	appType, err := AppType(context.Background(), "./testdata/foo", map[string]bool{})
+	appType, err := AppType(context.Background(), "./testdata/foo", map[string]bool{}, []string{})
 	assert.NoError(t, err)
 	assert.Equal(t, "Kustomize", appType)
 
-	appType, err = AppType(context.Background(), "./testdata/baz", map[string]bool{})
+	appType, err = AppType(context.Background(), "./testdata/baz", map[string]bool{}, []string{})
 	assert.NoError(t, err)
 	assert.Equal(t, "Helm", appType)
 
-	appType, err = AppType(context.Background(), "./testdata", map[string]bool{})
+	appType, err = AppType(context.Background(), "./testdata", map[string]bool{}, []string{})
 	assert.NoError(t, err)
 	assert.Equal(t, "Directory", appType)
 }
@@ -37,15 +37,15 @@ func TestAppType_Disabled(t *testing.T) {
 		string(v1alpha1.ApplicationSourceTypeKustomize): false,
 		string(v1alpha1.ApplicationSourceTypeHelm):      false,
 	}
-	appType, err := AppType(context.Background(), "./testdata/foo", enableManifestGeneration)
+	appType, err := AppType(context.Background(), "./testdata/foo", enableManifestGeneration, []string{})
 	assert.NoError(t, err)
 	assert.Equal(t, "Directory", appType)
 
-	appType, err = AppType(context.Background(), "./testdata/baz", enableManifestGeneration)
+	appType, err = AppType(context.Background(), "./testdata/baz", enableManifestGeneration, []string{})
 	assert.NoError(t, err)
 	assert.Equal(t, "Directory", appType)
 
-	appType, err = AppType(context.Background(), "./testdata", enableManifestGeneration)
+	appType, err = AppType(context.Background(), "./testdata", enableManifestGeneration, []string{})
 	assert.NoError(t, err)
 	assert.Equal(t, "Directory", appType)
 }
diff --git a/util/cmp/stream_test.go b/util/cmp/stream_test.go
index fb1b51375..b8d82edb7 100644
--- a/util/cmp/stream_test.go
+++ b/util/cmp/stream_test.go
@@ -60,7 +60,7 @@ func TestReceiveApplicationStream(t *testing.T) {
 			close(streamMock.messages)
 			os.RemoveAll(workdir)
 		}()
-		go streamMock.sendFile(context.Background(), t, appDir, streamMock, []string{"env1", "env2"})
+		go streamMock.sendFile(context.Background(), t, appDir, streamMock, []string{"env1", "env2"}, []string{"DUMMY.md", "dum*"})
 
 		// when
 		env, err := cmp.ReceiveRepoStream(context.Background(), streamMock, workdir)
@@ -77,16 +77,18 @@ func TestReceiveApplicationStream(t *testing.T) {
 		}
 		assert.Contains(t, names, "README.md")
 		assert.Contains(t, names, "applicationset")
+		assert.NotContains(t, names, "DUMMY.md")
+		assert.NotContains(t, names, "dummy")
 		assert.NotNil(t, env)
 	})
 }
 
-func (m *streamMock) sendFile(ctx context.Context, t *testing.T, basedir string, sender cmp.StreamSender, env []string) {
+func (m *streamMock) sendFile(ctx context.Context, t *testing.T, basedir string, sender cmp.StreamSender, env []string, excludedGlobs []string) {
 	t.Helper()
 	defer func() {
 		m.done <- true
 	}()
-	err := cmp.SendRepoStream(ctx, basedir, basedir, sender, env)
+	err := cmp.SendRepoStream(ctx, basedir, basedir, sender, env, excludedGlobs)
 	require.NoError(t, err)
 }
 
diff --git a/util/cmp/testdata/app/DUMMY.md b/util/cmp/testdata/app/DUMMY.md
new file mode 100644
index 000000000..e5fd3704b
--- /dev/null
+++ b/util/cmp/testdata/app/DUMMY.md
@@ -0,0 +1,1 @@
+This file is used to test the tar stream exclusions.
\ No newline at end of file
diff --git a/util/cmp/testdata/app/dummy/DUMMY2.md b/util/cmp/testdata/app/dummy/DUMMY2.md
new file mode 100644
index 000000000..45e5aa57c
--- /dev/null
+++ b/util/cmp/testdata/app/dummy/DUMMY2.md
@@ -0,0 +1,1 @@
+This is another file that should get excluded because the entire directory is excluded.
\ No newline at end of file