mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-02-27 13:08:46 +01:00
Compare commits
67 Commits
v2.1.3
...
release-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
903db5fe46 | ||
|
|
1d26f44f53 | ||
|
|
e577e25405 | ||
|
|
a92a153a49 | ||
|
|
45ddd05cef | ||
|
|
947bdd9efb | ||
|
|
4fd50ce8bd | ||
|
|
3fab7def3e | ||
|
|
5e6b788da9 | ||
|
|
26ac321f03 | ||
|
|
ea79ca4029 | ||
|
|
e7ca57b361 | ||
|
|
f3e7fbada8 | ||
|
|
01f069c1da | ||
|
|
4c8ca4f41e | ||
|
|
e19c351f10 | ||
|
|
0d74b6859d | ||
|
|
52f917a181 | ||
|
|
f4c22f5958 | ||
|
|
10491767cf | ||
|
|
7357cfdb58 | ||
|
|
2fe88150d6 | ||
|
|
836cde06ba | ||
|
|
db00e40b16 | ||
|
|
4803dfac1d | ||
|
|
5dbdaa4fe2 | ||
|
|
e13e887de8 | ||
|
|
b043629979 | ||
|
|
273a952e6c | ||
|
|
2600f52a66 | ||
|
|
2cefc00855 | ||
|
|
e25d3b5435 | ||
|
|
b921433112 | ||
|
|
96f63c3e2b | ||
|
|
d04dc9baed | ||
|
|
0ef556e0f5 | ||
|
|
d54361937b | ||
|
|
de6735c386 | ||
|
|
df2149bbac | ||
|
|
09529ee1ae | ||
|
|
5c51d5dae0 | ||
|
|
ec9b6f1689 | ||
|
|
b7d9f0071b | ||
|
|
2fdaf7a9ad | ||
|
|
5e64458c6b | ||
|
|
2475403af7 | ||
|
|
a1e14d48ab | ||
|
|
425d35c477 | ||
|
|
0d7c4cbe83 | ||
|
|
a408e299ff | ||
|
|
1acd1af8ef | ||
|
|
5679e4060e | ||
|
|
a346cf933e | ||
|
|
f249d530b5 | ||
|
|
46c1ef7a16 | ||
|
|
b4565fd7b2 | ||
|
|
a8a6fc8dda | ||
|
|
81024f8a89 | ||
|
|
f0201c3a99 | ||
|
|
d5c6608827 | ||
|
|
0564de77e6 | ||
|
|
e1eec8a9dc | ||
|
|
3d8d03f0a4 | ||
|
|
64f5c6aa85 | ||
|
|
f9e2fc9210 | ||
|
|
f9eac82928 | ||
|
|
bfbc19a583 |
7
.github/workflows/ci-build.yaml
vendored
7
.github/workflows/ci-build.yaml
vendored
@@ -9,6 +9,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'release-*'
|
||||
|
||||
env:
|
||||
# Golang version to use across CI steps
|
||||
@@ -71,10 +72,10 @@ jobs:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: v1.38.0
|
||||
args: --timeout 10m --exclude SA5011
|
||||
version: v1.46.2
|
||||
args: --timeout 10m --exclude SA5011 --verbose
|
||||
|
||||
test-go:
|
||||
name: Run unit tests for Go packages
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
run:
|
||||
timeout: 2m
|
||||
skip-files:
|
||||
- ".*\\.pb\\.go"
|
||||
skip-dirs:
|
||||
- pkg/client/
|
||||
- vendor/
|
||||
linters:
|
||||
enable:
|
||||
- vet
|
||||
- deadcode
|
||||
- goimports
|
||||
- varcheck
|
||||
- structcheck
|
||||
- ineffassign
|
||||
- unconvert
|
||||
- unparam
|
||||
linters-settings:
|
||||
goimports:
|
||||
local-prefixes: github.com/argoproj/argo-cd
|
||||
service:
|
||||
golangci-lint-version: 1.21.0
|
||||
1
USERS.md
1
USERS.md
@@ -154,3 +154,4 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Beleza Na Web](https://www.belezanaweb.com.br/)
|
||||
1. [MariaDB](https://mariadb.com)
|
||||
1. [Lightricks](https://www.lightricks.com/)
|
||||
1. [Snapp](https://snapp.ir/)
|
||||
@@ -2661,6 +2661,16 @@
|
||||
"type": "string",
|
||||
"name": "revision",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appName",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appProject",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3960,6 +3970,9 @@
|
||||
"appName": {
|
||||
"type": "string"
|
||||
},
|
||||
"appProject": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"$ref": "#/definitions/v1alpha1ApplicationSource"
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc/health/grpc_health_v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
cmdutil "github.com/argoproj/argo-cd/v2/cmd/util"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
@@ -63,14 +64,15 @@ func getPauseGenerationOnFailureForRequests() int {
|
||||
|
||||
func NewCommand() *cobra.Command {
|
||||
var (
|
||||
parallelismLimit int64
|
||||
listenPort int
|
||||
metricsPort int
|
||||
cacheSrc func() (*reposervercache.Cache, error)
|
||||
tlsConfigCustomizer tls.ConfigCustomizer
|
||||
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
|
||||
redisClient *redis.Client
|
||||
disableTLS bool
|
||||
parallelismLimit int64
|
||||
listenPort int
|
||||
metricsPort int
|
||||
cacheSrc func() (*reposervercache.Cache, error)
|
||||
tlsConfigCustomizer tls.ConfigCustomizer
|
||||
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
|
||||
redisClient *redis.Client
|
||||
disableTLS bool
|
||||
maxCombinedDirectoryManifestsSize string
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: cliName,
|
||||
@@ -90,13 +92,17 @@ func NewCommand() *cobra.Command {
|
||||
cache, err := cacheSrc()
|
||||
errors.CheckError(err)
|
||||
|
||||
maxCombinedDirectoryManifestsQuantity, err := resource.ParseQuantity(maxCombinedDirectoryManifestsSize)
|
||||
errors.CheckError(err)
|
||||
|
||||
metricsServer := metrics.NewMetricsServer()
|
||||
cacheutil.CollectMetrics(redisClient, metricsServer)
|
||||
server, err := reposerver.NewServer(metricsServer, cache, tlsConfigCustomizer, repository.RepoServerInitConstants{
|
||||
ParallelismLimit: parallelismLimit,
|
||||
ParallelismLimit: parallelismLimit,
|
||||
PauseGenerationAfterFailedGenerationAttempts: getPauseGenerationAfterFailedGenerationAttempts(),
|
||||
PauseGenerationOnFailureForMinutes: getPauseGenerationOnFailureForMinutes(),
|
||||
PauseGenerationOnFailureForRequests: getPauseGenerationOnFailureForRequests(),
|
||||
MaxCombinedDirectoryManifestsSize: maxCombinedDirectoryManifestsQuantity,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
@@ -160,6 +166,7 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().IntVar(&listenPort, "port", common.DefaultPortRepoServer, "Listen on given port for incoming connections")
|
||||
command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortRepoServerMetrics, "Start metrics server on given port")
|
||||
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")
|
||||
|
||||
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command)
|
||||
cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package admin
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -63,7 +64,10 @@ func NewProjectAllowListGenCommand() *cobra.Command {
|
||||
}()
|
||||
}
|
||||
|
||||
globalProj := generateProjectAllowList(clientConfig, clusterRoleFileName, projName)
|
||||
resourceList, err := getResourceList(clientConfig)
|
||||
errors.CheckError(err)
|
||||
globalProj, err := generateProjectAllowList(resourceList, clusterRoleFileName, projName)
|
||||
errors.CheckError(err)
|
||||
|
||||
yamlBytes, err := yaml.Marshal(globalProj)
|
||||
errors.CheckError(err)
|
||||
@@ -78,23 +82,38 @@ func NewProjectAllowListGenCommand() *cobra.Command {
|
||||
return command
|
||||
}
|
||||
|
||||
func generateProjectAllowList(clientConfig clientcmd.ClientConfig, clusterRoleFileName string, projName string) v1alpha1.AppProject {
|
||||
func getResourceList(clientConfig clientcmd.ClientConfig) ([]*metav1.APIResourceList, error) {
|
||||
config, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while creating client config: %s", err)
|
||||
}
|
||||
disco, err := discovery.NewDiscoveryClientForConfig(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while creating discovery client: %s", err)
|
||||
}
|
||||
serverResources, err := disco.ServerPreferredResources()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while getting server resources: %s", err)
|
||||
}
|
||||
return serverResources, nil
|
||||
}
|
||||
|
||||
func generateProjectAllowList(serverResources []*metav1.APIResourceList, clusterRoleFileName string, projName string) (*v1alpha1.AppProject, error) {
|
||||
yamlBytes, err := ioutil.ReadFile(clusterRoleFileName)
|
||||
errors.CheckError(err)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading cluster role file: %s", err)
|
||||
}
|
||||
var obj unstructured.Unstructured
|
||||
err = yaml.Unmarshal(yamlBytes, &obj)
|
||||
errors.CheckError(err)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error unmarshalling cluster role file yaml: %s", err)
|
||||
}
|
||||
|
||||
clusterRole := &rbacv1.ClusterRole{}
|
||||
err = scheme.Scheme.Convert(&obj, clusterRole, nil)
|
||||
errors.CheckError(err)
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
disco, err := discovery.NewDiscoveryClientForConfig(config)
|
||||
errors.CheckError(err)
|
||||
serverResources, err := disco.ServerPreferredResources()
|
||||
errors.CheckError(err)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting cluster role yaml into ClusterRole struct: %s", err)
|
||||
}
|
||||
|
||||
resourceList := make([]metav1.GroupKind, 0)
|
||||
for _, rule := range clusterRole.Rules {
|
||||
@@ -140,5 +159,5 @@ func generateProjectAllowList(clientConfig clientcmd.ClientConfig, clusterRoleFi
|
||||
Spec: v1alpha1.AppProjectSpec{},
|
||||
}
|
||||
globalProj.Spec.NamespaceResourceWhitelist = resourceList
|
||||
return globalProj
|
||||
return &globalProj, nil
|
||||
}
|
||||
|
||||
@@ -1,57 +1,20 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/undefinedlabs/go-mpatch"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/discovery"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
func TestProjectAllowListGen(t *testing.T) {
|
||||
useMock := true
|
||||
rules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
overrides := &clientcmd.ConfigOverrides{}
|
||||
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(rules, overrides)
|
||||
|
||||
if useMock {
|
||||
var patchClientConfig *mpatch.Patch
|
||||
patchClientConfig, err := mpatch.PatchInstanceMethodByName(reflect.TypeOf(clientConfig), "ClientConfig", func(*clientcmd.DeferredLoadingClientConfig) (*restclient.Config, error) {
|
||||
return nil, nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
patch, err := mpatch.PatchMethod(discovery.NewDiscoveryClientForConfig, func(c *restclient.Config) (*discovery.DiscoveryClient, error) {
|
||||
return &discovery.DiscoveryClient{LegacyPrefix: "/api"}, nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
var patchSeverPreferredResources *mpatch.Patch
|
||||
discoClient := &discovery.DiscoveryClient{}
|
||||
patchSeverPreferredResources, err = mpatch.PatchInstanceMethodByName(reflect.TypeOf(discoClient), "ServerPreferredResources", func(*discovery.DiscoveryClient) ([]*metav1.APIResourceList, error) {
|
||||
res := metav1.APIResource{
|
||||
Name: "services",
|
||||
Kind: "Service",
|
||||
}
|
||||
resourceList := []*metav1.APIResourceList{{APIResources: []metav1.APIResource{res}}}
|
||||
return resourceList, nil
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer func() {
|
||||
err = patchClientConfig.Unpatch()
|
||||
assert.NoError(t, err)
|
||||
err = patch.Unpatch()
|
||||
assert.NoError(t, err)
|
||||
err = patchSeverPreferredResources.Unpatch()
|
||||
err = patch.Unpatch()
|
||||
}()
|
||||
res := metav1.APIResource{
|
||||
Name: "services",
|
||||
Kind: "Service",
|
||||
}
|
||||
resourceList := []*metav1.APIResourceList{{APIResources: []metav1.APIResource{res}}}
|
||||
|
||||
globalProj := generateProjectAllowList(clientConfig, "testdata/test_clusterrole.yaml", "testproj")
|
||||
globalProj, err := generateProjectAllowList(resourceList, "testdata/test_clusterrole.yaml", "testproj")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, len(globalProj.Spec.NamespaceResourceWhitelist) > 0)
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -756,7 +757,7 @@ func getLocalObjectsString(app *argoappv1.Application, local, localRepoRoot, app
|
||||
KustomizeOptions: kustomizeOptions,
|
||||
KubeVersion: kubeVersion,
|
||||
Plugins: configManagementPlugins,
|
||||
}, true)
|
||||
}, true, resource.MustParse("0"))
|
||||
errors.CheckError(err)
|
||||
|
||||
return res.Manifests
|
||||
|
||||
@@ -200,7 +200,10 @@ func oauth2Login(ctx context.Context, port int, oidcSettings *settingspkg.OIDCCo
|
||||
// completionChan is to signal flow completed. Non-empty string indicates error
|
||||
completionChan := make(chan string)
|
||||
// stateNonce is an OAuth2 state nonce
|
||||
stateNonce := rand.RandString(10)
|
||||
// According to the spec (https://www.rfc-editor.org/rfc/rfc6749#section-10.10), this must be guessable with
|
||||
// probability <= 2^(-128). The following call generates one of 52^24 random strings, ~= 2^136 possibilities.
|
||||
stateNonce, err := rand.String(24)
|
||||
errors.CheckError(err)
|
||||
var tokenString string
|
||||
var refreshToken string
|
||||
|
||||
@@ -210,7 +213,8 @@ func oauth2Login(ctx context.Context, port int, oidcSettings *settingspkg.OIDCCo
|
||||
}
|
||||
|
||||
// PKCE implementation of https://tools.ietf.org/html/rfc7636
|
||||
codeVerifier := rand.RandStringCharset(43, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~")
|
||||
codeVerifier, err := rand.StringFromCharset(43, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~")
|
||||
errors.CheckError(err)
|
||||
codeChallengeHash := sha256.Sum256([]byte(codeVerifier))
|
||||
codeChallenge := base64.RawURLEncoding.EncodeToString(codeChallengeHash[:])
|
||||
|
||||
@@ -294,7 +298,8 @@ func oauth2Login(ctx context.Context, port int, oidcSettings *settingspkg.OIDCCo
|
||||
opts = append(opts, oauth2.SetAuthURLParam("code_challenge_method", "S256"))
|
||||
url = oauth2conf.AuthCodeURL(stateNonce, opts...)
|
||||
case oidcutil.GrantTypeImplicit:
|
||||
url = oidcutil.ImplicitFlowURL(oauth2conf, stateNonce, opts...)
|
||||
url, err = oidcutil.ImplicitFlowURL(oauth2conf, stateNonce, opts...)
|
||||
errors.CheckError(err)
|
||||
default:
|
||||
log.Fatalf("Unsupported grant type: %v", grantType)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
apiruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
@@ -355,8 +356,12 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
|
||||
},
|
||||
})
|
||||
} else {
|
||||
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, kube.GetResourceKey(live), func(child appv1.ResourceNode, appName string) {
|
||||
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, kube.GetResourceKey(live), func(child appv1.ResourceNode, appName string) bool {
|
||||
if !proj.IsResourcePermitted(schema.GroupKind{Group: child.ResourceRef.Group, Kind: child.ResourceRef.Kind}, child.Namespace, a.Spec.Destination) {
|
||||
return false
|
||||
}
|
||||
nodes = append(nodes, child)
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -366,16 +371,18 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
|
||||
orphanedNodes := make([]appv1.ResourceNode, 0)
|
||||
for k := range orphanedNodesMap {
|
||||
if k.Namespace != "" && proj.IsGroupKindPermitted(k.GroupKind(), true) && !isKnownOrphanedResourceExclusion(k, proj) {
|
||||
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, k, func(child appv1.ResourceNode, appName string) {
|
||||
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, k, func(child appv1.ResourceNode, appName string) bool {
|
||||
belongToAnotherApp := false
|
||||
if appName != "" {
|
||||
if _, exists, err := ctrl.appInformer.GetIndexer().GetByKey(ctrl.namespace + "/" + appName); exists && err == nil {
|
||||
belongToAnotherApp = true
|
||||
}
|
||||
}
|
||||
if !belongToAnotherApp {
|
||||
orphanedNodes = append(orphanedNodes, child)
|
||||
if belongToAnotherApp || !proj.IsResourcePermitted(schema.GroupKind{Group: child.ResourceRef.Group, Kind: child.ResourceRef.Kind}, child.Namespace, a.Spec.Destination) {
|
||||
return false
|
||||
}
|
||||
orphanedNodes = append(orphanedNodes, child)
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -665,6 +672,18 @@ func (ctrl *ApplicationController) processAppOperationQueueItem() (processNext b
|
||||
}
|
||||
app := origApp.DeepCopy()
|
||||
|
||||
if app.Operation != nil {
|
||||
// If we get here, we are about process an operation but we cannot rely on informer since it might has stale data.
|
||||
// So always retrieve the latest version to ensure it is not stale to avoid unnecessary syncing.
|
||||
// We cannot rely on informer since applications might be updated by both application controller and api server.
|
||||
freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Get(context.Background(), app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Errorf("Failed to retrieve latest application state: %v", err)
|
||||
return
|
||||
}
|
||||
app = freshApp
|
||||
}
|
||||
|
||||
if app.Operation != nil {
|
||||
ctrl.processRequestedAppOperation(app)
|
||||
} else if app.DeletionTimestamp != nil && app.CascadedDeletion() {
|
||||
@@ -1037,7 +1056,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
||||
}
|
||||
|
||||
ctrl.setOperationState(app, state)
|
||||
if state.Phase.Completed() && !app.Operation.Sync.DryRun {
|
||||
if state.Phase.Completed() && (app.Operation.Sync != nil && !app.Operation.Sync.DryRun) {
|
||||
// if we just completed an operation, force a refresh so that UI will report up-to-date
|
||||
// sync/health information
|
||||
if _, err := cache.MetaNamespaceKeyFunc(app); err == nil {
|
||||
@@ -1085,7 +1104,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
|
||||
}
|
||||
|
||||
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace)
|
||||
patchedApp, err := appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{})
|
||||
_, err = appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
// Stop retrying updating deleted application
|
||||
if apierr.IsNotFound(err) {
|
||||
@@ -1115,10 +1134,6 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
|
||||
ctrl.auditLogger.LogAppEvent(app, eventInfo, strings.Join(messages, " "))
|
||||
ctrl.metricsServer.IncSync(app, state)
|
||||
}
|
||||
// write back to informer in order to avoid stale cache
|
||||
if err := ctrl.appInformer.GetStore().Update(patchedApp); err != nil {
|
||||
log.Warnf("Fails to update informer: %v", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -1197,6 +1212,13 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
app.Status.Sync.Status = appv1.SyncStatusCodeUnknown
|
||||
app.Status.Health.Status = health.HealthStatusUnknown
|
||||
ctrl.persistAppStatus(origApp, &app.Status)
|
||||
|
||||
if err := ctrl.cache.SetAppResourcesTree(app.Name, &appv1.ApplicationTree{}); err != nil {
|
||||
log.Warnf("failed to set app resource tree: %v", err)
|
||||
}
|
||||
if err := ctrl.cache.SetAppManagedResources(app.Name, nil); err != nil {
|
||||
log.Warnf("failed to set app managed resources tree: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -135,12 +135,12 @@ func newFakeController(data *fakeData) *ApplicationController {
|
||||
mockStateCache.On("GetClusterCache", mock.Anything).Return(&clusterCacheMock, nil)
|
||||
mockStateCache.On("IterateHierarchy", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
|
||||
key := args[1].(kube.ResourceKey)
|
||||
action := args[2].(func(child argoappv1.ResourceNode, appName string))
|
||||
action := args[2].(func(child argoappv1.ResourceNode, appName string) bool)
|
||||
appName := ""
|
||||
if res, ok := data.namespacedResources[key]; ok {
|
||||
appName = res.AppName
|
||||
}
|
||||
action(argoappv1.ResourceNode{ResourceRef: argoappv1.ResourceRef{Kind: key.Kind, Group: key.Group, Namespace: key.Namespace, Name: key.Name}}, appName)
|
||||
_ = action(argoappv1.ResourceNode{ResourceRef: argoappv1.ResourceRef{Kind: key.Kind, Group: key.Group, Namespace: key.Namespace, Name: key.Name}}, appName)
|
||||
}).Return(nil)
|
||||
return ctrl
|
||||
}
|
||||
@@ -1083,12 +1083,10 @@ func TestProcessRequestedAppOperation_FailedNoRetries(t *testing.T) {
|
||||
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
|
||||
receivedPatch := map[string]interface{}{}
|
||||
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
patchedApp := &v1alpha1.Application{}
|
||||
if patchAction, ok := action.(kubetesting.PatchAction); ok {
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
|
||||
}
|
||||
return true, patchedApp, nil
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
ctrl.processRequestedAppOperation(app)
|
||||
@@ -1110,12 +1108,10 @@ func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) {
|
||||
fakeAppCs.Lock()
|
||||
defer fakeAppCs.Unlock()
|
||||
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
patchedApp := &v1alpha1.Application{}
|
||||
if patchAction, ok := action.(kubetesting.PatchAction); ok {
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
|
||||
}
|
||||
return true, patchedApp, nil
|
||||
return true, nil, nil
|
||||
})
|
||||
}()
|
||||
|
||||
@@ -1138,12 +1134,10 @@ func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) {
|
||||
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
|
||||
receivedPatch := map[string]interface{}{}
|
||||
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
patchedApp := &v1alpha1.Application{}
|
||||
if patchAction, ok := action.(kubetesting.PatchAction); ok {
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
|
||||
}
|
||||
return true, patchedApp, nil
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
ctrl.processRequestedAppOperation(app)
|
||||
@@ -1183,12 +1177,10 @@ func TestProcessRequestedAppOperation_RunningPreviouslyFailed(t *testing.T) {
|
||||
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
|
||||
receivedPatch := map[string]interface{}{}
|
||||
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
patchedApp := &v1alpha1.Application{}
|
||||
if patchAction, ok := action.(kubetesting.PatchAction); ok {
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
|
||||
}
|
||||
return true, patchedApp, nil
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
ctrl.processRequestedAppOperation(app)
|
||||
@@ -1218,12 +1210,10 @@ func TestProcessRequestedAppOperation_HasRetriesTerminated(t *testing.T) {
|
||||
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
|
||||
receivedPatch := map[string]interface{}{}
|
||||
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
patchedApp := &v1alpha1.Application{}
|
||||
if patchAction, ok := action.(kubetesting.PatchAction); ok {
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
|
||||
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
|
||||
}
|
||||
return true, patchedApp, nil
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
ctrl.processRequestedAppOperation(app)
|
||||
|
||||
8
controller/cache/cache.go
vendored
8
controller/cache/cache.go
vendored
@@ -56,7 +56,7 @@ type LiveStateCache interface {
|
||||
// Returns synced cluster cache
|
||||
GetClusterCache(server string) (clustercache.ClusterCache, error)
|
||||
// Executes give callback against resource specified by the key and all its children
|
||||
IterateHierarchy(server string, key kube.ResourceKey, action func(child appv1.ResourceNode, appName string)) error
|
||||
IterateHierarchy(server string, key kube.ResourceKey, action func(child appv1.ResourceNode, appName string) bool) error
|
||||
// Returns state of live nodes which correspond for target nodes of specified application.
|
||||
GetManagedLiveObjs(a *appv1.Application, targetObjs []*unstructured.Unstructured) (map[kube.ResourceKey]*unstructured.Unstructured, error)
|
||||
// IterateResources iterates all resource stored in cache
|
||||
@@ -371,13 +371,13 @@ func (c *liveStateCache) IsNamespaced(server string, gk schema.GroupKind) (bool,
|
||||
return clusterInfo.IsNamespaced(gk)
|
||||
}
|
||||
|
||||
func (c *liveStateCache) IterateHierarchy(server string, key kube.ResourceKey, action func(child appv1.ResourceNode, appName string)) error {
|
||||
func (c *liveStateCache) IterateHierarchy(server string, key kube.ResourceKey, action func(child appv1.ResourceNode, appName string) bool) error {
|
||||
clusterInfo, err := c.getSyncedCluster(server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clusterInfo.IterateHierarchy(key, func(resource *clustercache.Resource, namespaceResources map[kube.ResourceKey]*clustercache.Resource) {
|
||||
action(asResourceNode(resource), getApp(resource, namespaceResources))
|
||||
clusterInfo.IterateHierarchy(key, func(resource *clustercache.Resource, namespaceResources map[kube.ResourceKey]*clustercache.Resource) bool {
|
||||
return action(asResourceNode(resource), getApp(resource, namespaceResources))
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
4
controller/cache/mocks/LiveStateCache.go
vendored
4
controller/cache/mocks/LiveStateCache.go
vendored
@@ -178,11 +178,11 @@ func (_m *LiveStateCache) IsNamespaced(server string, gk schema.GroupKind) (bool
|
||||
}
|
||||
|
||||
// IterateHierarchy provides a mock function with given fields: server, key, action
|
||||
func (_m *LiveStateCache) IterateHierarchy(server string, key kube.ResourceKey, action func(v1alpha1.ResourceNode, string)) error {
|
||||
func (_m *LiveStateCache) IterateHierarchy(server string, key kube.ResourceKey, action func(v1alpha1.ResourceNode, string) bool) error {
|
||||
ret := _m.Called(server, key, action)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, kube.ResourceKey, func(v1alpha1.ResourceNode, string)) error); ok {
|
||||
if rf, ok := ret.Get(0).(func(string, kube.ResourceKey, func(v1alpha1.ResourceNode, string) bool) error); ok {
|
||||
r0 = rf(server, key, action)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
|
||||
@@ -152,6 +152,11 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
helmOptions, err := m.settingsMgr.GetHelmSettings()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ts.AddCheckpoint("build_options_ms")
|
||||
serverVersion, apiGroups, err := m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server)
|
||||
if err != nil {
|
||||
@@ -174,6 +179,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
|
||||
ApiVersions: argo.APIGroupsToVersions(apiGroups),
|
||||
VerifySignature: verifySignature,
|
||||
HelmRepoCreds: permittedHelmCredentials,
|
||||
HelmOptions: helmOptions,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -127,7 +127,13 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
|
||||
}
|
||||
|
||||
atomic.AddUint64(&syncIdPrefix, 1)
|
||||
syncId := fmt.Sprintf("%05d-%s", syncIdPrefix, rand.RandString(5))
|
||||
randSuffix, err := rand.String(5)
|
||||
if err != nil {
|
||||
state.Phase = common.OperationError
|
||||
state.Message = fmt.Sprintf("Failed generate random sync ID: %v", err)
|
||||
return
|
||||
}
|
||||
syncId := fmt.Sprintf("%05d-%s", syncIdPrefix, randSuffix)
|
||||
|
||||
logEntry := log.WithFields(log.Fields{"application": app.Name, "syncId": syncId})
|
||||
initialResourcesRes := make([]common.ResourceSyncResult, 0)
|
||||
|
||||
@@ -194,6 +194,10 @@ data:
|
||||
kustomize.version.v3.5.1: /custom-tools/kustomize_3_5_1
|
||||
kustomize.version.v3.5.4: /custom-tools/kustomize_3_5_4
|
||||
|
||||
# Comma delimited list of additional custom remote values file schemes (http are https are allowed by default).
|
||||
# Change to empty value if you want to disable remote values files altogether.
|
||||
helm.valuesFileSchemes: http, https
|
||||
|
||||
# The metadata.label key name where Argo CD injects the app name as a tracking label (optional).
|
||||
# Tracking labels are used to determine which resources need to be deleted when pruning.
|
||||
# If omitted, Argo CD injects the app name into the label: 'app.kubernetes.io/instance'
|
||||
|
||||
@@ -103,4 +103,8 @@ data:
|
||||
reposerver.repo.cache.expiration: "24h0m0s"
|
||||
# Cache expiration default (default 24h0m0s)
|
||||
reposerver.default.cache.expiration: "24h0m0s"
|
||||
|
||||
# Max combined manifest file size for a single directory-type Application. In-memory manifest representation may be as
|
||||
# much as 300x the manifest file size. Limit this to stay within the memory limits of the repo-server while allowing
|
||||
# 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'
|
||||
|
||||
@@ -14,3 +14,5 @@ data:
|
||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
|
||||
@@ -396,6 +396,8 @@ data:
|
||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
@@ -39,6 +39,48 @@ the three components (argocd-server, argocd-repo-server, argocd-application-cont
|
||||
API server can enforce the use of TLS 1.2 using the flag: `--tlsminversion 1.2`.
|
||||
Communication with Redis is performed over plain HTTP by default. TLS can be setup with command line arguments.
|
||||
|
||||
## Git & Helm Repositories
|
||||
|
||||
Git and helm repositories are managed by a stand-alone service, called the repo-server. The
|
||||
repo-server does not carry any Kubernetes privileges and does not store credentials to any services
|
||||
(including git). The repo-server is responsible for cloning repositories which have been permitted
|
||||
and trusted by Argo CD operators, and generating kubernetes manifests at a given path in the
|
||||
repository. For performance and bandwidth efficiency, the repo-server maintains local clones of
|
||||
these repositories so that subsequent commits to the repository are efficiently downloaded.
|
||||
|
||||
There are security considerations when configuring git repositories that Argo CD is permitted to
|
||||
deploy from. In short, gaining unauthorized write access to a git repository trusted by Argo CD
|
||||
will have serious security implications outlined below.
|
||||
|
||||
### Unauthorized Deployments
|
||||
|
||||
Since Argo CD deploys the Kubernetes resources defined in git, an attacker with access to a trusted
|
||||
git repo would be able to affect the Kubernetes resources which are deployed. For example, an
|
||||
attacker could update the deployment manifest deploy malicious container images to the environment,
|
||||
or delete resources in git causing them to be pruned in the live environment.
|
||||
|
||||
### Tool command invocation
|
||||
|
||||
In addition to raw YAML, Argo CD natively supports two popular Kubernetes config management tools,
|
||||
helm and kustomize. When rendering manifests, Argo CD executes these config management tools
|
||||
(i.e. `helm template`, `kustomize build`) to generate the manifests. It is possible that an attacker
|
||||
with write access to a trusted git repository may construct malicious helm charts or kustomizations
|
||||
that attempt to read files out-of-tree. This includes adjacent git repos, as well as files on the
|
||||
repo-server itself. Whether or not this is a risk to your organization depends on if the contents
|
||||
in the git repos are sensitive in nature. By default, the repo-server itself does not contain
|
||||
sensitive information, but might be configured with Config Management Plugins which do
|
||||
(e.g. decryption keys). If such plugins are used, extreme care must be taken to ensure the
|
||||
repository contents can be trusted at all times.
|
||||
|
||||
### Remote bases and helm chart dependencies
|
||||
|
||||
Argo CD's repository allow-list only restricts the initial repository which is cloned. However, both
|
||||
kustomize and helm contain features to reference and follow *additional* repositories
|
||||
(e.g. kustomize remote bases, helm chart dependencies), of which might not be in the repository
|
||||
allow-list. Argo CD operators must understand that users with write access to trusted git
|
||||
repositories could reference other remote git repositories containing Kubernetes resources not
|
||||
easily searchable or auditable in the configured git repositories.
|
||||
|
||||
## Sensitive Information
|
||||
|
||||
### Secrets
|
||||
@@ -154,3 +196,44 @@ Payloads from webhook events are considered untrusted. Argo CD only examines the
|
||||
the involved applications of the webhook event (e.g. which repo was modified), then refreshes
|
||||
the related application for reconciliation. This refresh is the same refresh which occurs regularly
|
||||
at three minute intervals, just fast-tracked by the webhook event.
|
||||
|
||||
## Limiting Directory App Memory Usage
|
||||
|
||||
> >2.2.10, 2.1.16, >2.3.5
|
||||
|
||||
Directory-type Applications (those whose source is raw JSON or YAML files) can consume significant
|
||||
[repo-server](architecture.md#repository-server) memory, depending on the size and structure of the YAML files.
|
||||
|
||||
To avoid over-using memory in the repo-server (potentially causing a crash and denial of service), set the
|
||||
`reposerver.max.combined.directory.manifests.size` config option in [argocd-cmd-params-cm](argocd-cmd-params-cm.yaml).
|
||||
|
||||
This option limits the combined size of all JSON or YAML files in an individual app. Note that the in-memory
|
||||
representation of a manifest may be as much as 300x the size of the manifest on disk. Also note that the limit is per
|
||||
Application. If manifests are generated for multiple applications at once, memory usage will be higher.
|
||||
|
||||
**Example:**
|
||||
|
||||
Suppose your repo-server has a 10G memory limit, and you have ten Applications which use raw JSON or YAML files. To
|
||||
calculate the max safe combined file size per Application, divide 10G by 300 * 10 Apps (300 being the worst-case memory
|
||||
growth factor for the manifests).
|
||||
|
||||
```
|
||||
10G / 300 * 10 = 3M
|
||||
```
|
||||
|
||||
So a reasonably safe configuration for this setup would be a 3M limit per app.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-cmd-params-cm
|
||||
data:
|
||||
reposerver.max.combined.directory.manifests.size: '3M'
|
||||
```
|
||||
|
||||
The 300x ratio assumes a maliciously-crafted manifest file. If you only want to protect against accidental excessive
|
||||
memory use, it is probably safe to use a smaller ratio.
|
||||
|
||||
Keep in mind that if a malicious user can create additional Applications, they can increase the total memory usage.
|
||||
Grant [App creation privileges](rbac.md) carefully.
|
||||
|
||||
@@ -13,27 +13,28 @@ argocd-repo-server [flags]
|
||||
### Options
|
||||
|
||||
```
|
||||
--default-cache-expiration duration Cache expiration default (default 24h0m0s)
|
||||
--disable-tls Disable TLS on the gRPC endpoint
|
||||
-h, --help help for argocd-repo-server
|
||||
--logformat string Set the logging format. One of: text|json (default "text")
|
||||
--loglevel string Set the logging level. One of: debug|info|warn|error (default "info")
|
||||
--metrics-port int Start metrics server on given port (default 8084)
|
||||
--parallelismlimit int Limit on number of concurrent manifests generate requests. Any value less the 1 means no limit.
|
||||
--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.
|
||||
--redis-client-certificate string Path to Redis client certificate (e.g. /etc/certs/redis/client.crt).
|
||||
--redis-client-key string Path to Redis client key (e.g. /etc/certs/redis/client.crt).
|
||||
--redis-insecure-skip-tls-verify Skip Redis server certificate validation.
|
||||
--redis-use-tls Use TLS when connecting to Redis.
|
||||
--redisdb int Redis database.
|
||||
--repo-cache-expiration duration Cache expiration for repo state, incl. app lists, app details, manifest generation, revision meta-data (default 24h0m0s)
|
||||
--revision-cache-expiration duration Cache expiration for cached revision (default 3m0s)
|
||||
--sentinel stringArray Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379).
|
||||
--sentinelmaster string Redis sentinel master group name. (default "master")
|
||||
--tlsciphers string The list of acceptable ciphers to be used when establishing TLS connections. Use 'list' to list available ciphers. (default "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_256_GCM_SHA384")
|
||||
--tlsmaxversion string The maximum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.3")
|
||||
--tlsminversion string The minimum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.2")
|
||||
--default-cache-expiration duration Cache expiration default (default 24h0m0s)
|
||||
--disable-tls Disable TLS on the gRPC endpoint
|
||||
-h, --help help for argocd-repo-server
|
||||
--logformat string Set the logging format. One of: text|json (default "text")
|
||||
--loglevel string Set the logging level. One of: debug|info|warn|error (default "info")
|
||||
--max-combined-directory-manifests-size string Max combined size of manifest files in a directory-type Application (default "10M")
|
||||
--metrics-port int Start metrics server on given port (default 8084)
|
||||
--parallelismlimit int Limit on number of concurrent manifests generate requests. Any value less the 1 means no limit.
|
||||
--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.
|
||||
--redis-client-certificate string Path to Redis client certificate (e.g. /etc/certs/redis/client.crt).
|
||||
--redis-client-key string Path to Redis client key (e.g. /etc/certs/redis/client.crt).
|
||||
--redis-insecure-skip-tls-verify Skip Redis server certificate validation.
|
||||
--redis-use-tls Use TLS when connecting to Redis.
|
||||
--redisdb int Redis database.
|
||||
--repo-cache-expiration duration Cache expiration for repo state, incl. app lists, app details, manifest generation, revision meta-data (default 24h0m0s)
|
||||
--revision-cache-expiration duration Cache expiration for cached revision (default 3m0s)
|
||||
--sentinel stringArray Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379).
|
||||
--sentinelmaster string Redis sentinel master group name. (default "master")
|
||||
--tlsciphers string The list of acceptable ciphers to be used when establishing TLS connections. Use 'list' to list available ciphers. (default "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_256_GCM_SHA384")
|
||||
--tlsmaxversion string The maximum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.3")
|
||||
--tlsminversion string The minimum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.2")
|
||||
```
|
||||
|
||||
|
||||
@@ -5,12 +5,16 @@
|
||||
- [Config Management Tools Integrations (proposal)](#config-management-tools-integrations-proposal)
|
||||
- [Argo CD Extensions (proposal)](#argo-cd-extensions-proposal)
|
||||
- [Project scoped repository and clusters (proposal)](#project-scoped-repository-and-clusters-proposal)
|
||||
- [Core Argo CD (proposal)](#core-argo-cd-aka-gitops-agent-proposal)
|
||||
- [v2.3 and beyond](#v23-and-beyond)
|
||||
- [Application Details Page Usability](#application-details-page-usability)
|
||||
- [Cluster Management User Interface](#cluster-management-user-interface)
|
||||
- [Input Forms UI Refresh](#input-forms-ui-refresh)
|
||||
- [Merge ApplicationSet controller into Argo CD](#merge-applicationset-controller-into-argo-cd)
|
||||
- [Merge Argo CD Notifications into Argo CD](#merge-argo-cd-notifications-into-argo-cd)
|
||||
- [Merge Argo CD Image Updater into Argo CD](#merge-argo-cd-image-updater-into-argo-cd)
|
||||
- [Compact Resources Tree](#compact-resources-tree)
|
||||
- [Multi-tenancy improvements](#multi-tenancy-improvements)
|
||||
- [GitOps Engine Enhancements](#gitops-engine-enhancements)
|
||||
- [Completed](#completed)
|
||||
- [✅ Core Argo CD (proposal)](#core-argo-cd-aka-gitops-agent-proposal)
|
||||
- [✅ Core Functionality Bug Fixes](#-core-functionality-bug-fixes)
|
||||
- [✅ Performance](#-performance)
|
||||
- [✅ ApplicationSet](#-applicationset)
|
||||
@@ -20,7 +24,6 @@
|
||||
- [✅ Automated Registry Monitoring](#-automated-registry-monitoring)
|
||||
- [✅ Projects Enhancements](#-projects-enhancements)
|
||||
|
||||
|
||||
## v2.2
|
||||
|
||||
### Config Management Tools Integrations ([proposal](https://github.com/argoproj/argo-cd/pull/5927))
|
||||
@@ -44,17 +47,33 @@ Instead of asking an administrator to change Argo CD settings end users can perf
|
||||
|
||||
## v2.3 and beyond
|
||||
|
||||
### Application Details Page Usability
|
||||
### Input Forms UI Refresh
|
||||
|
||||
Application details page has accumulated multiple usability and feature requests such as
|
||||
[Node view](https://github.com/argoproj/argo-cd/issues/1483),
|
||||
Network view ([1](https://github.com/argoproj/argo-cd/issues/2892), [2](https://github.com/argoproj/argo-cd/issues/2338))
|
||||
[etc](https://github.com/argoproj/argo-cd/issues/2199).
|
||||
Improved design of the input forms in Argo CD Web UI: https://www.figma.com/file/IIlsFqqmM5UhqMVul9fQNq/Argo-CD?node-id=0%3A1
|
||||
|
||||
### Cluster Management User Interface
|
||||
### Merge ApplicationSet controller into Argo CD
|
||||
|
||||
The ApplicationSet functionality is available in Argo CD out-of-the-box ([#7351](https://github.com/argoproj/argo-cd/issues/7351)).
|
||||
The Argo CD UI/CLI/API allows to manage ApplicationSet resources same as Argo CD Applications ([#7352](https://github.com/argoproj/argo-cd/issues/7352)).
|
||||
|
||||
### Merge Argo CD Notifications into Argo CD
|
||||
|
||||
The [Argo CD Notifications](https://github.com/argoproj-labs/argocd-notifications) should be merged into Argo CD and available out-of-the-box: [#7350](https://github.com/argoproj/argo-cd/issues/7350)
|
||||
|
||||
### Merge Argo CD Image Updater into Argo CD
|
||||
|
||||
The [Argo CD Image Updater](https://github.com/argoproj-labs/argocd-image-updater) should be merged into Argo CD and available out-of-the-box: [#7385](https://github.com/argoproj/argo-cd/issues/7385)
|
||||
|
||||
### Compact resources tree
|
||||
|
||||
An ability to collaps leaf resources tree to improve visualization of very large applications: [#7349](https://github.com/argoproj/argo-cd/issues/7349)
|
||||
|
||||
### Multi-tenancy improvements
|
||||
|
||||
The multi-tenancy improvements that allow end-users to create Argo CD applications using Kubernetes directly without accessing Argo CD API.
|
||||
* [Applications outside argocd namespace](https://github.com/argoproj/argo-cd/pull/6409)
|
||||
* [AppSource](https://github.com/argoproj-labs/appsource)
|
||||
|
||||
Argo CD has information about whole clusters, not just applications in it.
|
||||
We need to provide a user interface for cluster administrators that visualize cluster level resources.
|
||||
|
||||
### GitOps Engine Enhancements
|
||||
|
||||
@@ -109,7 +128,7 @@ to improve user experience.
|
||||
|
||||
To make Argo CD successful we need to build tools that enable Argo CD administrators to handle scalability and performance issues in a self-service model.
|
||||
|
||||
That includes more metrics, out of the box alerts and a cluster management user interface.
|
||||
That includes more metrics, out-of-the-box alerts and a cluster management user interface.
|
||||
|
||||
|
||||
### ✅ Argo CD Notifications
|
||||
|
||||
@@ -35,8 +35,8 @@ metadata:
|
||||
app.kubernetes.io/name: argocd-cm
|
||||
app.kubernetes.io/part-of: argocd
|
||||
data:
|
||||
kustomize.buildOptions: --load_restrictor LoadRestrictionsNone
|
||||
kustomize.buildOptions.v3.9.1: --output /tmp
|
||||
kustomize.buildOptions: --load-restrictor LoadRestrictionsNone
|
||||
kustomize.buildOptions.v4.4.0: --output /tmp
|
||||
```
|
||||
## Custom Kustomize versions
|
||||
|
||||
|
||||
5
go.mod
5
go.mod
@@ -7,8 +7,8 @@ require (
|
||||
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible
|
||||
github.com/alicebob/miniredis/v2 v2.14.2
|
||||
github.com/argoproj/gitops-engine v0.4.1
|
||||
github.com/argoproj/pkg v0.9.1
|
||||
github.com/argoproj/gitops-engine v0.4.3
|
||||
github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0
|
||||
github.com/bombsimon/logrusr v1.0.0
|
||||
github.com/bradleyfalzon/ghinstallation v1.1.1
|
||||
github.com/casbin/casbin v1.9.1
|
||||
@@ -59,7 +59,6 @@ require (
|
||||
github.com/spf13/cobra v1.1.3
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/undefinedlabs/go-mpatch v1.0.6
|
||||
github.com/vmihailenco/msgpack/v5 v5.1.0 // indirect
|
||||
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e
|
||||
|
||||
10
go.sum
10
go.sum
@@ -96,10 +96,10 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/argoproj/gitops-engine v0.4.1 h1:kBAAWVUBfnhD40sRIEr3XcUcPZHODOmwSXSpySmVWR0=
|
||||
github.com/argoproj/gitops-engine v0.4.1/go.mod h1:EdFe8qIOqsmbyxRhtIydU4BUeyZ4VTsY6R3XVQhU9LA=
|
||||
github.com/argoproj/pkg v0.9.1 h1:osfOS3QkzfRf+W43lbCZb0o0bzrBweQhL+U3rgEg+5M=
|
||||
github.com/argoproj/pkg v0.9.1/go.mod h1:ra+bQPmbVAoEL+gYSKesuigt4m49i3Qa3mE/xQcjCiA=
|
||||
github.com/argoproj/gitops-engine v0.4.3 h1:QLAnFVmPPL1F5hmqb/5rABOAW7sb/fERaeeFz78kbKE=
|
||||
github.com/argoproj/gitops-engine v0.4.3/go.mod h1:EdFe8qIOqsmbyxRhtIydU4BUeyZ4VTsY6R3XVQhU9LA=
|
||||
github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0 h1:Cfp7rO/HpVxnwlRqJe0jHiBbZ77ZgXhB6HWlYD02Xdc=
|
||||
github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0/go.mod h1:ra+bQPmbVAoEL+gYSKesuigt4m49i3Qa3mE/xQcjCiA=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
@@ -741,8 +741,6 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/undefinedlabs/go-mpatch v1.0.6 h1:h8q5ORH/GaOE1Se1DMhrOyljXZEhRcROO7agMqWXCOY=
|
||||
github.com/undefinedlabs/go-mpatch v1.0.6/go.mod h1:TyJZDQ/5AgyN7FSLiBJ8RO9u2c6wbtRvK827b6AVqY4=
|
||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
set -eux -o pipefail
|
||||
|
||||
GO111MODULE=on go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.38.0
|
||||
GO111MODULE=on go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.2
|
||||
|
||||
@@ -14,3 +14,5 @@ data:
|
||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.1.3
|
||||
newTag: v2.1.16
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -98,6 +98,12 @@ spec:
|
||||
name: argocd-cmd-params-cm
|
||||
key: reposerver.default.cache.expiration
|
||||
optional: true
|
||||
- name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: argocd-cmd-params-cm
|
||||
key: reposerver.max.combined.directory.manifests.size
|
||||
optional: true
|
||||
- name: HELM_CACHE_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_CONFIG_HOME
|
||||
|
||||
@@ -2735,7 +2735,7 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
@@ -2743,6 +2743,8 @@ data:
|
||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
@@ -2982,13 +2984,19 @@ spec:
|
||||
key: reposerver.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: reposerver.max.combined.directory.manifests.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: HELM_CACHE_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_CONFIG_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -3185,7 +3193,7 @@ spec:
|
||||
key: controller.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -11,4 +11,4 @@ resources:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.1.3
|
||||
newTag: v2.1.16
|
||||
|
||||
@@ -11,7 +11,7 @@ patchesStrategicMerge:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.1.3
|
||||
newTag: v2.1.16
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/dex
|
||||
|
||||
@@ -3377,7 +3377,7 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
@@ -3385,6 +3385,8 @@ data:
|
||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
@@ -3684,7 +3686,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -3895,13 +3897,19 @@ spec:
|
||||
key: reposerver.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: reposerver.max.combined.directory.manifests.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: HELM_CACHE_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_CONFIG_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -4154,7 +4162,7 @@ spec:
|
||||
key: server.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -4350,7 +4358,7 @@ spec:
|
||||
key: controller.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -764,7 +764,7 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
@@ -772,6 +772,8 @@ data:
|
||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
@@ -1071,7 +1073,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -1282,13 +1284,19 @@ spec:
|
||||
key: reposerver.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: reposerver.max.combined.directory.manifests.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: HELM_CACHE_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_CONFIG_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1541,7 +1549,7 @@ spec:
|
||||
key: server.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -1737,7 +1745,7 @@ spec:
|
||||
key: controller.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -2847,7 +2847,7 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
@@ -2855,6 +2855,8 @@ data:
|
||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
@@ -3049,7 +3051,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -3224,13 +3226,19 @@ spec:
|
||||
key: reposerver.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: reposerver.max.combined.directory.manifests.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: HELM_CACHE_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_CONFIG_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -3479,7 +3487,7 @@ spec:
|
||||
key: server.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -3669,7 +3677,7 @@ spec:
|
||||
key: controller.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -234,7 +234,7 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
@@ -242,6 +242,8 @@ data:
|
||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
labels:
|
||||
@@ -436,7 +438,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
@@ -611,13 +613,19 @@ spec:
|
||||
key: reposerver.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
key: reposerver.max.combined.directory.manifests.size
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
- name: HELM_CACHE_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_CONFIG_HOME
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -866,7 +874,7 @@ spec:
|
||||
key: server.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -1056,7 +1064,7 @@ spec:
|
||||
key: controller.default.cache.expiration
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.1.3
|
||||
image: quay.io/argoproj/argocd:v2.1.16
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -100,7 +100,11 @@ func (c *client) executeRequest(fullMethodName string, msg []byte, md metadata.M
|
||||
}
|
||||
|
||||
func (c *client) startGRPCProxy() (*grpc.Server, net.Listener, error) {
|
||||
serverAddr := fmt.Sprintf("%s/argocd-%s.sock", os.TempDir(), rand.RandString(16))
|
||||
randSuffix, err := rand.String(16)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to generate random socket filename: %w", err)
|
||||
}
|
||||
serverAddr := fmt.Sprintf("%s/argocd-%s.sock", os.TempDir(), randSuffix)
|
||||
ln, err := net.Listen("unix", serverAddr)
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -39,6 +39,8 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
type RepoAppsQuery struct {
|
||||
Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
|
||||
Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"`
|
||||
AppName string `protobuf:"bytes,3,opt,name=appName,proto3" json:"appName,omitempty"`
|
||||
AppProject string `protobuf:"bytes,4,opt,name=appProject,proto3" json:"appProject,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -91,6 +93,20 @@ func (m *RepoAppsQuery) GetRevision() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *RepoAppsQuery) GetAppName() string {
|
||||
if m != nil {
|
||||
return m.AppName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *RepoAppsQuery) GetAppProject() string {
|
||||
if m != nil {
|
||||
return m.AppProject
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// AppInfo contains application type and app file path
|
||||
type AppInfo struct {
|
||||
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||
@@ -151,6 +167,7 @@ func (m *AppInfo) GetPath() string {
|
||||
type RepoAppDetailsQuery struct {
|
||||
Source *v1alpha1.ApplicationSource `protobuf:"bytes,1,opt,name=source,proto3" json:"source,omitempty"`
|
||||
AppName string `protobuf:"bytes,2,opt,name=appName,proto3" json:"appName,omitempty"`
|
||||
AppProject string `protobuf:"bytes,3,opt,name=appProject,proto3" json:"appProject,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -203,6 +220,13 @@ func (m *RepoAppDetailsQuery) GetAppName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *RepoAppDetailsQuery) GetAppProject() string {
|
||||
if m != nil {
|
||||
return m.AppProject
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// RepoAppsResponse contains applications of specified repository
|
||||
type RepoAppsResponse struct {
|
||||
Items []*AppInfo `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
|
||||
@@ -654,76 +678,77 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_8d38260443475705 = []byte{
|
||||
// 1093 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x4f, 0x6f, 0x1b, 0x45,
|
||||
0x14, 0xd7, 0x36, 0xa9, 0x9b, 0x4c, 0xfe, 0xd4, 0x9d, 0x84, 0xb2, 0xb8, 0x69, 0x1a, 0x4d, 0x4b,
|
||||
0x15, 0xa2, 0xb2, 0xdb, 0x18, 0x21, 0xaa, 0x22, 0x40, 0x69, 0x12, 0xb5, 0x11, 0x11, 0x81, 0xad,
|
||||
0xc2, 0x01, 0x81, 0xd0, 0x64, 0xfd, 0x62, 0x2f, 0x59, 0xef, 0x4c, 0x67, 0xc6, 0x0b, 0x56, 0xd5,
|
||||
0x0b, 0x27, 0x24, 0xb8, 0x20, 0x84, 0xd4, 0x1b, 0x07, 0x90, 0x38, 0xf0, 0x45, 0x38, 0x22, 0xf1,
|
||||
0x05, 0x50, 0xc4, 0xe7, 0x40, 0x68, 0x66, 0xd6, 0xbb, 0xeb, 0xc4, 0x76, 0x52, 0x11, 0x72, 0x9b,
|
||||
0xf9, 0xbd, 0x37, 0xef, 0xfd, 0xde, 0xcf, 0x6f, 0xde, 0x78, 0x11, 0x91, 0x20, 0x52, 0x10, 0xbe,
|
||||
0x00, 0xce, 0x64, 0xa4, 0x98, 0xe8, 0x96, 0x96, 0x1e, 0x17, 0x4c, 0x31, 0x8c, 0x0a, 0xa4, 0x36,
|
||||
0xdf, 0x64, 0x4d, 0x66, 0x60, 0x5f, 0xaf, 0xac, 0x47, 0x6d, 0xa1, 0xc9, 0x58, 0x33, 0x06, 0x9f,
|
||||
0xf2, 0xc8, 0xa7, 0x49, 0xc2, 0x14, 0x55, 0x11, 0x4b, 0x64, 0x66, 0x25, 0x07, 0xf7, 0xa4, 0x17,
|
||||
0x31, 0x63, 0x0d, 0x99, 0x00, 0x3f, 0x5d, 0xf5, 0x9b, 0x90, 0x80, 0xa0, 0x0a, 0x1a, 0x99, 0xcf,
|
||||
0x76, 0x33, 0x52, 0xad, 0xce, 0x9e, 0x17, 0xb2, 0xb6, 0x4f, 0x85, 0x49, 0xf1, 0x85, 0x59, 0xbc,
|
||||
0x1e, 0x36, 0xfc, 0xb4, 0xee, 0xf3, 0x83, 0xa6, 0x3e, 0x2f, 0x7d, 0xca, 0x79, 0x1c, 0x85, 0x26,
|
||||
0xbe, 0x9f, 0xae, 0xd2, 0x98, 0xb7, 0xe8, 0xf1, 0x68, 0x9b, 0x27, 0x44, 0x33, 0x05, 0x9d, 0x58,
|
||||
0x38, 0x79, 0x0f, 0xcd, 0x04, 0xc0, 0xd9, 0x1a, 0xe7, 0xf2, 0xa3, 0x0e, 0x88, 0x2e, 0xc6, 0x68,
|
||||
0x5c, 0x3b, 0xb9, 0xce, 0x92, 0xb3, 0x3c, 0x19, 0x98, 0x35, 0xae, 0xa1, 0x09, 0x01, 0x69, 0x24,
|
||||
0x23, 0x96, 0xb8, 0x17, 0x0c, 0x9e, 0xef, 0xc9, 0x2a, 0xba, 0xb4, 0xc6, 0xf9, 0x56, 0xb2, 0xcf,
|
||||
0xf4, 0x51, 0xd5, 0xe5, 0xd0, 0x3b, 0xaa, 0xd7, 0x1a, 0xe3, 0x54, 0xb5, 0xb2, 0x63, 0x66, 0x4d,
|
||||
0x9e, 0x3b, 0x68, 0x2e, 0x4b, 0xba, 0x01, 0x8a, 0x46, 0x71, 0x96, 0xba, 0x89, 0x2a, 0x92, 0x75,
|
||||
0x44, 0x68, 0x23, 0x4c, 0xd5, 0x77, 0xbc, 0xa2, 0x46, 0xaf, 0x57, 0xa3, 0x59, 0x7c, 0x1e, 0x36,
|
||||
0xbc, 0xb4, 0xee, 0xf1, 0x83, 0xa6, 0xa7, 0x15, 0xf3, 0x4a, 0x8a, 0x79, 0x3d, 0xc5, 0xbc, 0xb5,
|
||||
0x02, 0x7c, 0x6c, 0xc2, 0x06, 0x59, 0x78, 0xec, 0xa2, 0x4b, 0x94, 0xf3, 0x0f, 0x68, 0x1b, 0x32,
|
||||
0x5e, 0xbd, 0x2d, 0x79, 0x07, 0x55, 0x7b, 0x72, 0x04, 0x20, 0x39, 0x4b, 0x24, 0xe0, 0xd7, 0xd0,
|
||||
0xc5, 0x48, 0x41, 0x5b, 0xba, 0xce, 0xd2, 0xd8, 0xf2, 0x54, 0x7d, 0xce, 0x2b, 0x89, 0x98, 0x95,
|
||||
0x1e, 0x58, 0x0f, 0xb2, 0x8e, 0x26, 0xf5, 0xf1, 0xe1, 0x4a, 0x12, 0x34, 0xbd, 0xcf, 0x34, 0x15,
|
||||
0xd8, 0x17, 0x20, 0xad, 0x2c, 0x13, 0x41, 0x1f, 0x46, 0x7e, 0x1e, 0x47, 0x97, 0x0d, 0x89, 0x30,
|
||||
0x04, 0x39, 0xfa, 0x57, 0xe9, 0x48, 0x10, 0x49, 0x51, 0x46, 0xbe, 0xd7, 0x36, 0x4e, 0xa5, 0xfc,
|
||||
0x92, 0x89, 0x86, 0x3b, 0x66, 0x6d, 0xbd, 0x3d, 0xbe, 0x85, 0x66, 0xa4, 0x6c, 0x7d, 0x28, 0xa2,
|
||||
0x94, 0x2a, 0x78, 0x1f, 0xba, 0xee, 0xb8, 0x71, 0xe8, 0x07, 0x75, 0x84, 0x28, 0x91, 0x10, 0x76,
|
||||
0x04, 0xb8, 0x17, 0x0d, 0xcb, 0x7c, 0x8f, 0xef, 0xa0, 0x2b, 0x2a, 0x96, 0xeb, 0x71, 0x04, 0x89,
|
||||
0x5a, 0x07, 0xa1, 0x36, 0xa8, 0xa2, 0x6e, 0xc5, 0x44, 0x39, 0x6e, 0xc0, 0x2b, 0xa8, 0xda, 0x07,
|
||||
0xea, 0x94, 0x97, 0x8c, 0xf3, 0x31, 0x3c, 0x6f, 0xa1, 0xc9, 0xfe, 0x16, 0x32, 0x35, 0x22, 0x8b,
|
||||
0x99, 0xfa, 0x16, 0xd0, 0x24, 0x24, 0x74, 0x2f, 0x86, 0x9d, 0x30, 0x72, 0xa7, 0x0c, 0xbd, 0x02,
|
||||
0xc0, 0x77, 0xd1, 0x9c, 0xed, 0x9c, 0x35, 0xce, 0x4b, 0x75, 0x4e, 0x9b, 0x00, 0x83, 0x4c, 0x78,
|
||||
0x09, 0x4d, 0xe5, 0xf0, 0xd6, 0x86, 0x3b, 0xb3, 0xe4, 0x2c, 0x8f, 0x05, 0x65, 0x08, 0xdf, 0x43,
|
||||
0x2f, 0x17, 0xdb, 0x44, 0x2a, 0x1a, 0xc7, 0xa6, 0xb5, 0xb6, 0x36, 0xdc, 0x59, 0xe3, 0x3d, 0xcc,
|
||||
0x8c, 0xdf, 0x45, 0xb5, 0xdc, 0xb4, 0x99, 0x28, 0x10, 0x5c, 0x44, 0x12, 0x1e, 0x50, 0x09, 0xbb,
|
||||
0x22, 0x76, 0x2f, 0x1b, 0x52, 0x23, 0x3c, 0xf0, 0x3c, 0xba, 0xc8, 0x05, 0xfb, 0xaa, 0xeb, 0x56,
|
||||
0x8d, 0xab, 0xdd, 0x90, 0x59, 0x34, 0xad, 0x9b, 0xa4, 0xd7, 0xa5, 0xe4, 0x57, 0x07, 0x5d, 0xd1,
|
||||
0xc0, 0xba, 0x00, 0xaa, 0x20, 0x80, 0x27, 0x1d, 0x90, 0x0a, 0x7f, 0x5a, 0xea, 0x9b, 0xa9, 0xfa,
|
||||
0xa3, 0xff, 0x76, 0xa1, 0x82, 0xbc, 0xef, 0xb3, 0x0e, 0xbc, 0x8a, 0x2a, 0x1d, 0x2e, 0x41, 0xa8,
|
||||
0xac, 0x8f, 0xb3, 0x9d, 0xfe, 0x75, 0x42, 0x01, 0x0d, 0xb9, 0x93, 0xc4, 0x5d, 0xd3, 0x7e, 0x13,
|
||||
0x41, 0x01, 0x90, 0x27, 0x96, 0xe8, 0x2e, 0x6f, 0x9c, 0x17, 0xd1, 0xfa, 0x3f, 0xb3, 0x36, 0xa7,
|
||||
0x05, 0x1f, 0x83, 0x48, 0xa3, 0x10, 0xf0, 0x77, 0x0e, 0x1a, 0xdf, 0x8e, 0xa4, 0xc2, 0x2f, 0x95,
|
||||
0xaf, 0x74, 0x7e, 0x81, 0x6b, 0xdb, 0x67, 0xc5, 0x42, 0x27, 0x21, 0x37, 0xbe, 0xfe, 0xf3, 0xef,
|
||||
0x1f, 0x2e, 0x5c, 0xc5, 0xf3, 0xe6, 0x91, 0x48, 0x57, 0x8b, 0x59, 0x1c, 0x81, 0xfc, 0xe6, 0x82,
|
||||
0x83, 0xbf, 0x75, 0xd0, 0xd8, 0x43, 0x18, 0xca, 0xe6, 0xcc, 0x34, 0x21, 0x37, 0x0d, 0x93, 0xeb,
|
||||
0xf8, 0xda, 0x20, 0x26, 0xfe, 0x53, 0xbd, 0x7b, 0x86, 0x7f, 0x74, 0x50, 0x55, 0xf3, 0x0e, 0x4a,
|
||||
0xb6, 0xf3, 0x11, 0x6a, 0x61, 0x94, 0x50, 0xf8, 0x33, 0x34, 0x61, 0x69, 0xed, 0x0f, 0xa5, 0x53,
|
||||
0xed, 0x87, 0xf7, 0x25, 0x59, 0x36, 0x21, 0x09, 0x5e, 0x1a, 0x51, 0xb1, 0x2f, 0x74, 0xc8, 0xb6,
|
||||
0x0d, 0xaf, 0x1f, 0x00, 0xfc, 0xca, 0xd1, 0xf0, 0xf9, 0x2b, 0x59, 0x5b, 0x18, 0x64, 0xca, 0xef,
|
||||
0xe2, 0xa9, 0xd2, 0x51, 0x9d, 0xe2, 0x7b, 0x07, 0xcd, 0x3c, 0x04, 0x55, 0xbc, 0x84, 0xf8, 0xc6,
|
||||
0x80, 0xc8, 0xe5, 0x57, 0xb2, 0x46, 0x86, 0x3b, 0xe4, 0x04, 0xde, 0x36, 0x04, 0xde, 0x24, 0x77,
|
||||
0x07, 0x13, 0xb0, 0xcf, 0xa0, 0x89, 0xb3, 0x1b, 0x6c, 0x1b, 0x2a, 0x0d, 0x1b, 0xe1, 0xbe, 0xb3,
|
||||
0x82, 0x53, 0x43, 0xe9, 0x11, 0xc4, 0xed, 0xf5, 0x16, 0x15, 0x6a, 0xa8, 0xcc, 0x8b, 0x65, 0xb8,
|
||||
0x70, 0xcf, 0x49, 0x78, 0x86, 0xc4, 0x32, 0xbe, 0x3d, 0x4a, 0x85, 0x16, 0xc4, 0xed, 0xd0, 0xa6,
|
||||
0x79, 0xee, 0xa0, 0x8a, 0x9d, 0x5e, 0xf8, 0xfa, 0xd1, 0x8c, 0x7d, 0x53, 0xed, 0x0c, 0xaf, 0xc2,
|
||||
0xab, 0x86, 0xe3, 0x02, 0x19, 0xd8, 0x6b, 0xf7, 0xcd, 0xf0, 0xd0, 0x57, 0xf3, 0x27, 0x07, 0x55,
|
||||
0x7b, 0x14, 0x7a, 0x67, 0xcf, 0x8f, 0x24, 0x39, 0x99, 0x24, 0xfe, 0xc5, 0x41, 0x15, 0x3b, 0x51,
|
||||
0x8f, 0xf3, 0xea, 0x9b, 0xb4, 0x67, 0xc8, 0x6b, 0xd5, 0xfe, 0xc0, 0xb5, 0x11, 0x6d, 0x6e, 0xa8,
|
||||
0x3c, 0x2b, 0x84, 0xfc, 0xcd, 0x41, 0xd5, 0x1e, 0x9d, 0xe1, 0x42, 0xfe, 0x5f, 0x84, 0xbd, 0x17,
|
||||
0x23, 0x8c, 0x29, 0xaa, 0x6c, 0x40, 0x0c, 0x0a, 0x86, 0x5d, 0x01, 0xf7, 0x28, 0x9c, 0x37, 0xff,
|
||||
0x6d, 0x3b, 0x63, 0x57, 0x46, 0xcd, 0x58, 0x2d, 0x48, 0x0b, 0x55, 0x6d, 0x8a, 0x92, 0x1e, 0x2f,
|
||||
0x9c, 0xec, 0xe6, 0x29, 0x92, 0xe1, 0xa7, 0x68, 0xf6, 0x63, 0x1a, 0x47, 0x5a, 0x59, 0xfb, 0xcf,
|
||||
0x12, 0x5f, 0x3b, 0x36, 0x49, 0x8a, 0x7f, 0x9c, 0x23, 0xb2, 0xd5, 0x4d, 0xb6, 0x3b, 0xe4, 0xd6,
|
||||
0xa8, 0x7b, 0x9d, 0x66, 0xa9, 0xac, 0x92, 0x0f, 0x36, 0x7f, 0x3f, 0x5c, 0x74, 0xfe, 0x38, 0x5c,
|
||||
0x74, 0xfe, 0x3a, 0x5c, 0x74, 0x3e, 0x79, 0xeb, 0x74, 0x5f, 0x42, 0xa1, 0xf9, 0x6b, 0x58, 0xfa,
|
||||
0x66, 0xd9, 0xab, 0x98, 0x8f, 0x96, 0x37, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xa8, 0xce, 0xfa,
|
||||
0x47, 0xd3, 0x0d, 0x00, 0x00,
|
||||
// 1118 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x6e, 0x1c, 0x45,
|
||||
0x10, 0xd6, 0xf8, 0x67, 0x6d, 0xb7, 0x7f, 0xb2, 0x69, 0x9b, 0x30, 0x6c, 0x1c, 0xc7, 0x9a, 0x84,
|
||||
0xc8, 0x58, 0x61, 0x26, 0x5e, 0x84, 0x88, 0x82, 0x40, 0x72, 0x6c, 0x2b, 0xb1, 0xb0, 0x70, 0x98,
|
||||
0xc8, 0x1c, 0x10, 0x08, 0xb5, 0x67, 0x6b, 0x77, 0x27, 0x9e, 0x9d, 0xee, 0x74, 0xf7, 0x0e, 0xac,
|
||||
0xa2, 0x5c, 0x38, 0x21, 0xc1, 0x05, 0x21, 0x24, 0x6e, 0x1c, 0x40, 0xe2, 0xc0, 0x0b, 0xf0, 0x08,
|
||||
0x1c, 0x91, 0x78, 0x01, 0x64, 0xf1, 0x1c, 0x08, 0x75, 0xf7, 0xec, 0xcc, 0xac, 0xf7, 0xc7, 0x8e,
|
||||
0x70, 0x7c, 0xeb, 0xfe, 0xaa, 0xb6, 0xea, 0xab, 0xaf, 0xab, 0xab, 0x77, 0x90, 0x23, 0x80, 0x27,
|
||||
0xc0, 0x3d, 0x0e, 0x8c, 0x8a, 0x50, 0x52, 0xde, 0x29, 0x2c, 0x5d, 0xc6, 0xa9, 0xa4, 0x18, 0xe5,
|
||||
0x48, 0x65, 0xa9, 0x41, 0x1b, 0x54, 0xc3, 0x9e, 0x5a, 0x19, 0x8f, 0xca, 0x72, 0x83, 0xd2, 0x46,
|
||||
0x04, 0x1e, 0x61, 0xa1, 0x47, 0xe2, 0x98, 0x4a, 0x22, 0x43, 0x1a, 0x8b, 0xd4, 0xea, 0x1c, 0xdd,
|
||||
0x15, 0x6e, 0x48, 0xb5, 0x35, 0xa0, 0x1c, 0xbc, 0x64, 0xc3, 0x6b, 0x40, 0x0c, 0x9c, 0x48, 0xa8,
|
||||
0xa5, 0x3e, 0x7b, 0x8d, 0x50, 0x36, 0xdb, 0x87, 0x6e, 0x40, 0x5b, 0x1e, 0xe1, 0x3a, 0xc5, 0x13,
|
||||
0xbd, 0x78, 0x33, 0xa8, 0x79, 0x49, 0xd5, 0x63, 0x47, 0x0d, 0xf5, 0x7b, 0xe1, 0x11, 0xc6, 0xa2,
|
||||
0x30, 0xd0, 0xf1, 0xbd, 0x64, 0x83, 0x44, 0xac, 0x49, 0xfa, 0xa3, 0xed, 0x9c, 0x12, 0x4d, 0x17,
|
||||
0x74, 0x6a, 0xe1, 0x4e, 0x07, 0xcd, 0xfb, 0xc0, 0xe8, 0x26, 0x63, 0xe2, 0xa3, 0x36, 0xf0, 0x0e,
|
||||
0xc6, 0x68, 0x42, 0x39, 0xd9, 0xd6, 0xaa, 0xb5, 0x36, 0xe3, 0xeb, 0x35, 0xae, 0xa0, 0x69, 0x0e,
|
||||
0x49, 0x28, 0x42, 0x1a, 0xdb, 0x63, 0x1a, 0xcf, 0xf6, 0xd8, 0x46, 0x53, 0x84, 0xb1, 0x0f, 0x49,
|
||||
0x0b, 0xec, 0x71, 0x6d, 0xea, 0x6e, 0xf1, 0x0a, 0x42, 0x84, 0xb1, 0x47, 0x9c, 0x3e, 0x81, 0x40,
|
||||
0xda, 0x13, 0xda, 0x58, 0x40, 0x9c, 0x0d, 0x34, 0xb5, 0xc9, 0xd8, 0x6e, 0x5c, 0xa7, 0x2a, 0xa9,
|
||||
0xec, 0x30, 0xe8, 0x26, 0x55, 0x6b, 0x85, 0x31, 0x22, 0x9b, 0x69, 0x42, 0xbd, 0x76, 0x7e, 0xb7,
|
||||
0xd0, 0x62, 0x4a, 0x77, 0x1b, 0x24, 0x09, 0xa3, 0x94, 0x74, 0x03, 0x95, 0x04, 0x6d, 0xf3, 0xc0,
|
||||
0x44, 0x98, 0xad, 0xee, 0xbb, 0xb9, 0x3a, 0x6e, 0x57, 0x1d, 0xbd, 0xf8, 0x3c, 0xa8, 0xb9, 0x49,
|
||||
0xd5, 0x65, 0x47, 0x0d, 0x57, 0x69, 0xed, 0x16, 0xb4, 0x76, 0xbb, 0x5a, 0xbb, 0x9b, 0x39, 0xf8,
|
||||
0x58, 0x87, 0xf5, 0xd3, 0xf0, 0xc5, 0x6a, 0xc7, 0x46, 0x55, 0x3b, 0xde, 0x57, 0xed, 0x7b, 0xa8,
|
||||
0xdc, 0x15, 0xda, 0x07, 0xc1, 0x68, 0x2c, 0x00, 0xbf, 0x81, 0x26, 0x43, 0x09, 0x2d, 0x61, 0x5b,
|
||||
0xab, 0xe3, 0x6b, 0xb3, 0xd5, 0x45, 0xb7, 0x70, 0x3c, 0xa9, 0x34, 0xbe, 0xf1, 0x70, 0xb6, 0xd0,
|
||||
0x8c, 0xfa, 0xf9, 0xf0, 0x33, 0x72, 0xd0, 0x5c, 0x9d, 0x2a, 0xaa, 0x50, 0xe7, 0x20, 0x8c, 0x6c,
|
||||
0xd3, 0x7e, 0x0f, 0xe6, 0xfc, 0x3c, 0x81, 0x2e, 0x69, 0x12, 0x41, 0x00, 0x62, 0xf4, 0x79, 0xb7,
|
||||
0x05, 0xf0, 0x38, 0x2f, 0x33, 0xdb, 0x2b, 0x1b, 0x23, 0x42, 0x7c, 0x41, 0x79, 0x2d, 0xad, 0x32,
|
||||
0xdb, 0xe3, 0x9b, 0x68, 0x5e, 0x88, 0xe6, 0x23, 0x1e, 0x26, 0x44, 0xc2, 0x07, 0xd0, 0x49, 0x0f,
|
||||
0xbd, 0x17, 0x54, 0x11, 0xc2, 0x58, 0x40, 0xd0, 0xe6, 0x60, 0x4f, 0x6a, 0x96, 0xd9, 0x1e, 0xdf,
|
||||
0x46, 0x97, 0x65, 0x24, 0xb6, 0xa2, 0x10, 0x62, 0xb9, 0x05, 0x5c, 0x6e, 0x13, 0x49, 0xec, 0x92,
|
||||
0x8e, 0xd2, 0x6f, 0xc0, 0xeb, 0xa8, 0xdc, 0x03, 0xaa, 0x94, 0x53, 0xda, 0xb9, 0x0f, 0xcf, 0x5a,
|
||||
0x6c, 0xa6, 0xb7, 0xc5, 0x74, 0x8d, 0xc8, 0x60, 0xba, 0xbe, 0x65, 0x34, 0x03, 0x31, 0x39, 0x8c,
|
||||
0x60, 0x3f, 0x08, 0xed, 0x59, 0x4d, 0x2f, 0x07, 0xf0, 0x1d, 0xb4, 0x68, 0x3a, 0x6b, 0x53, 0x9d,
|
||||
0x6c, 0x56, 0xe7, 0x9c, 0x0e, 0x30, 0xc8, 0x84, 0x57, 0xd1, 0x6c, 0x06, 0xef, 0x6e, 0xdb, 0xf3,
|
||||
0xab, 0xd6, 0xda, 0xb8, 0x5f, 0x84, 0xf0, 0x5d, 0xf4, 0x6a, 0xbe, 0x8d, 0x85, 0x24, 0x51, 0xa4,
|
||||
0x5b, 0x6f, 0x77, 0xdb, 0x5e, 0xd0, 0xde, 0xc3, 0xcc, 0xf8, 0x7d, 0x54, 0xc9, 0x4c, 0x3b, 0xb1,
|
||||
0x04, 0xce, 0x78, 0x28, 0xe0, 0x3e, 0x11, 0x70, 0xc0, 0x23, 0xfb, 0x92, 0x26, 0x35, 0xc2, 0x03,
|
||||
0x2f, 0xa1, 0x49, 0xc6, 0xe9, 0x97, 0x1d, 0xbb, 0xac, 0x5d, 0xcd, 0xc6, 0x59, 0x40, 0x73, 0xaa,
|
||||
0x49, 0xba, 0x5d, 0xea, 0xfc, 0x6a, 0xa1, 0xcb, 0x0a, 0xd8, 0xe2, 0x40, 0x24, 0xf8, 0xf0, 0xb4,
|
||||
0x0d, 0x42, 0xe2, 0x4f, 0x0b, 0x7d, 0x33, 0x5b, 0x7d, 0xf8, 0xff, 0x2e, 0x9c, 0x9f, 0xf5, 0x7d,
|
||||
0xda, 0x81, 0x57, 0x50, 0xa9, 0xcd, 0x04, 0x70, 0x99, 0xf6, 0x71, 0xba, 0x53, 0xa7, 0x13, 0x70,
|
||||
0xa8, 0x89, 0xfd, 0x38, 0xea, 0xe8, 0xf6, 0x9b, 0xf6, 0x73, 0xc0, 0x79, 0x6a, 0x88, 0x1e, 0xb0,
|
||||
0xda, 0x45, 0x11, 0xad, 0xfe, 0xbb, 0x60, 0x72, 0x1a, 0xf0, 0x31, 0xf0, 0x24, 0x0c, 0x00, 0x7f,
|
||||
0x6b, 0xa1, 0x89, 0xbd, 0x50, 0x48, 0xfc, 0x4a, 0xf1, 0x4a, 0x67, 0x17, 0xb8, 0xb2, 0x77, 0x5e,
|
||||
0x2c, 0x54, 0x12, 0xe7, 0xfa, 0x57, 0x7f, 0xfd, 0xf3, 0xfd, 0xd8, 0x15, 0xbc, 0xa4, 0x9f, 0x9f,
|
||||
0x64, 0x23, 0x9f, 0xf2, 0x21, 0x88, 0xaf, 0xc7, 0x2c, 0xfc, 0x8d, 0x85, 0xc6, 0x1f, 0xc0, 0x50,
|
||||
0x36, 0xe7, 0xa6, 0x89, 0x73, 0x43, 0x33, 0xb9, 0x86, 0xaf, 0x0e, 0x62, 0xe2, 0x3d, 0x53, 0xbb,
|
||||
0xe7, 0xf8, 0x07, 0x0b, 0x95, 0x15, 0x6f, 0xbf, 0x60, 0xbb, 0x18, 0xa1, 0x96, 0x47, 0x09, 0x85,
|
||||
0x3f, 0x43, 0xd3, 0x86, 0x56, 0x7d, 0x28, 0x9d, 0x72, 0x2f, 0x5c, 0x17, 0xce, 0x9a, 0x0e, 0xe9,
|
||||
0xe0, 0xd5, 0x11, 0x15, 0x7b, 0x5c, 0x85, 0x6c, 0x99, 0xf0, 0xea, 0x01, 0xc0, 0xaf, 0x9d, 0x0c,
|
||||
0x9f, 0xbd, 0xbf, 0x95, 0xe5, 0x41, 0xa6, 0xec, 0x2e, 0x9e, 0x29, 0x1d, 0x51, 0x29, 0xbe, 0xb3,
|
||||
0xd0, 0xfc, 0x03, 0x90, 0xf9, 0x4b, 0x89, 0xaf, 0x0f, 0x88, 0x5c, 0x7c, 0x45, 0x2b, 0xce, 0x70,
|
||||
0x87, 0x8c, 0xc0, 0xbb, 0x9a, 0xc0, 0xdb, 0xce, 0x9d, 0xc1, 0x04, 0xcc, 0x33, 0xa9, 0xe3, 0x1c,
|
||||
0xf8, 0x7b, 0x9a, 0x4a, 0xcd, 0x44, 0xb8, 0x67, 0xad, 0xe3, 0x44, 0x53, 0x7a, 0x08, 0x51, 0x6b,
|
||||
0xab, 0x49, 0xb8, 0x1c, 0x2a, 0xf3, 0x4a, 0x11, 0xce, 0xdd, 0x33, 0x12, 0xae, 0x26, 0xb1, 0x86,
|
||||
0x6f, 0x8d, 0x52, 0xa1, 0x09, 0x51, 0x2b, 0x30, 0x69, 0x7e, 0xb4, 0x50, 0xc9, 0x4c, 0x2f, 0x7c,
|
||||
0xed, 0x64, 0xc6, 0x9e, 0xa9, 0x76, 0x8e, 0x57, 0xe1, 0x75, 0xcd, 0x71, 0xd9, 0x19, 0xd8, 0x6b,
|
||||
0xf7, 0xf4, 0xf0, 0x50, 0x57, 0xf3, 0x27, 0x0b, 0x95, 0xbb, 0x14, 0xba, 0xbf, 0xbd, 0x38, 0x92,
|
||||
0xce, 0xe9, 0x24, 0xf1, 0x2f, 0x16, 0x2a, 0x99, 0x89, 0xda, 0xcf, 0xab, 0x67, 0xd2, 0x9e, 0x23,
|
||||
0xaf, 0x0d, 0x73, 0xc0, 0x95, 0x11, 0x6d, 0xae, 0xa9, 0x3c, 0xcf, 0x85, 0xfc, 0xcd, 0x42, 0xe5,
|
||||
0x2e, 0x9d, 0xe1, 0x42, 0xbe, 0x2c, 0xc2, 0xee, 0x8b, 0x11, 0xc6, 0x04, 0x95, 0xb6, 0x21, 0x02,
|
||||
0x09, 0xc3, 0xae, 0x80, 0x7d, 0x12, 0xce, 0x9a, 0xff, 0x96, 0x99, 0xb1, 0xeb, 0xa3, 0x66, 0xac,
|
||||
0x12, 0xa4, 0x89, 0xca, 0x26, 0x45, 0x41, 0x8f, 0x17, 0x4e, 0x76, 0xe3, 0x0c, 0xc9, 0xf0, 0x33,
|
||||
0xb4, 0xf0, 0x31, 0x89, 0x42, 0xa5, 0xac, 0xf9, 0x67, 0x89, 0xaf, 0xf6, 0x4d, 0x92, 0xfc, 0x1f,
|
||||
0xe7, 0x88, 0x6c, 0x55, 0x9d, 0xed, 0xb6, 0x73, 0x73, 0xd4, 0xbd, 0x4e, 0xd2, 0x54, 0x46, 0xc9,
|
||||
0xfb, 0x3b, 0x7f, 0x1c, 0xaf, 0x58, 0x7f, 0x1e, 0xaf, 0x58, 0x7f, 0x1f, 0xaf, 0x58, 0x9f, 0xbc,
|
||||
0x73, 0xb6, 0x6f, 0xac, 0x40, 0xff, 0x35, 0x2c, 0x7c, 0x0d, 0x1d, 0x96, 0xf4, 0xe7, 0xd0, 0x5b,
|
||||
0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x9e, 0xe7, 0xda, 0x2d, 0x0e, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -1328,6 +1353,20 @@ func (m *RepoAppsQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.AppProject) > 0 {
|
||||
i -= len(m.AppProject)
|
||||
copy(dAtA[i:], m.AppProject)
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.AppProject)))
|
||||
i--
|
||||
dAtA[i] = 0x22
|
||||
}
|
||||
if len(m.AppName) > 0 {
|
||||
i -= len(m.AppName)
|
||||
copy(dAtA[i:], m.AppName)
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.AppName)))
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
}
|
||||
if len(m.Revision) > 0 {
|
||||
i -= len(m.Revision)
|
||||
copy(dAtA[i:], m.Revision)
|
||||
@@ -1410,6 +1449,13 @@ func (m *RepoAppDetailsQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.AppProject) > 0 {
|
||||
i -= len(m.AppProject)
|
||||
copy(dAtA[i:], m.AppProject)
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.AppProject)))
|
||||
i--
|
||||
dAtA[i] = 0x1a
|
||||
}
|
||||
if len(m.AppName) > 0 {
|
||||
i -= len(m.AppName)
|
||||
copy(dAtA[i:], m.AppName)
|
||||
@@ -1803,6 +1849,14 @@ func (m *RepoAppsQuery) Size() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
l = len(m.AppName)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
l = len(m.AppProject)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
@@ -1843,6 +1897,10 @@ func (m *RepoAppDetailsQuery) Size() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
l = len(m.AppProject)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
@@ -2103,6 +2161,70 @@ func (m *RepoAppsQuery) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
m.Revision = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AppName", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.AppName = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 4:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AppProject", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.AppProject = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipRepository(dAtA[iNdEx:])
|
||||
@@ -2337,6 +2459,38 @@ func (m *RepoAppDetailsQuery) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
m.AppName = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field AppProject", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.AppProject = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipRepository(dAtA[iNdEx:])
|
||||
|
||||
@@ -27,6 +27,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/ap
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,Command,Args
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,Command,Command
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ExecProviderConfig,Args
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,HelmOptions,ValuesFileSchemes
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,HostInfo,ResourcesInfo
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,JWTTokens,Items
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,Operation,Info
|
||||
@@ -61,6 +62,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/ap
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSourceJsonnet,TLAs
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ClusterCacheInfo,APIsCount
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ConnectionState,ModifiedAt
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,HelmOptions,ValuesFileSchemes
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,JWTToken,ExpiresAt
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,JWTToken,IssuedAt
|
||||
API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,KustomizeOptions,BinaryPath
|
||||
|
||||
@@ -313,11 +313,15 @@ func (proj AppProject) IsGroupKindPermitted(gk schema.GroupKind, namespaced bool
|
||||
|
||||
// IsLiveResourcePermitted returns whether a live resource found in the cluster is permitted by an AppProject
|
||||
func (proj AppProject) IsLiveResourcePermitted(un *unstructured.Unstructured, server string) bool {
|
||||
if !proj.IsGroupKindPermitted(un.GroupVersionKind().GroupKind(), un.GetNamespace() != "") {
|
||||
return proj.IsResourcePermitted(un.GroupVersionKind().GroupKind(), un.GetNamespace(), ApplicationDestination{Server: server})
|
||||
}
|
||||
|
||||
func (proj AppProject) IsResourcePermitted(groupKind schema.GroupKind, namespace string, dest ApplicationDestination) bool {
|
||||
if !proj.IsGroupKindPermitted(groupKind, namespace != "") {
|
||||
return false
|
||||
}
|
||||
if un.GetNamespace() != "" {
|
||||
return proj.IsDestinationPermitted(ApplicationDestination{Server: server, Namespace: un.GetNamespace()})
|
||||
if namespace != "" {
|
||||
return proj.IsDestinationPermitted(ApplicationDestination{Server: dest.Server, Name: dest.Name, Namespace: namespace})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -36,12 +36,12 @@ var (
|
||||
|
||||
func init() {
|
||||
if envQPS := os.Getenv(EnvK8sClientQPS); envQPS != "" {
|
||||
if qps, err := strconv.ParseFloat(envQPS, 32); err != nil {
|
||||
if qps, err := strconv.ParseFloat(envQPS, 32); err == nil {
|
||||
K8sClientConfigQPS = float32(qps)
|
||||
}
|
||||
}
|
||||
if envBurst := os.Getenv(EnvK8sClientBurst); envBurst != "" {
|
||||
if burst, err := strconv.Atoi(envBurst); err != nil {
|
||||
if burst, err := strconv.Atoi(envBurst); err == nil {
|
||||
K8sClientConfigBurst = burst
|
||||
}
|
||||
} else {
|
||||
@@ -49,7 +49,7 @@ func init() {
|
||||
}
|
||||
|
||||
if envMaxConn := os.Getenv(EnvK8sClientMaxIdleConnections); envMaxConn != "" {
|
||||
if maxConn, err := strconv.Atoi(envMaxConn); err != nil {
|
||||
if maxConn, err := strconv.Atoi(envMaxConn); err == nil {
|
||||
K8sMaxIdleConnections = maxConn
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -588,6 +588,11 @@ message HelmFileParameter {
|
||||
optional string path = 2;
|
||||
}
|
||||
|
||||
// HelmOptions holds helm options
|
||||
message HelmOptions {
|
||||
repeated string valuesFileSchemes = 1;
|
||||
}
|
||||
|
||||
// HelmParameter is a parameter that's passed to helm template during manifest generation
|
||||
message HelmParameter {
|
||||
// Name is the name of the Helm parameter
|
||||
|
||||
@@ -51,6 +51,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GnuPGPublicKeyList": schema_pkg_apis_application_v1alpha1_GnuPGPublicKeyList(ref),
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HealthStatus": schema_pkg_apis_application_v1alpha1_HealthStatus(ref),
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmFileParameter": schema_pkg_apis_application_v1alpha1_HelmFileParameter(ref),
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmOptions": schema_pkg_apis_application_v1alpha1_HelmOptions(ref),
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmParameter": schema_pkg_apis_application_v1alpha1_HelmParameter(ref),
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HostInfo": schema_pkg_apis_application_v1alpha1_HostInfo(ref),
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HostResourceInfo": schema_pkg_apis_application_v1alpha1_HostResourceInfo(ref),
|
||||
@@ -2052,6 +2053,34 @@ func schema_pkg_apis_application_v1alpha1_HelmFileParameter(ref common.Reference
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_application_v1alpha1_HelmOptions(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "HelmOptions holds helm options",
|
||||
Type: []string{"object"},
|
||||
Properties: map[string]spec.Schema{
|
||||
"ValuesFileSchemes": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"ValuesFileSchemes"},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func schema_pkg_apis_application_v1alpha1_HelmParameter(ref common.ReferenceCallback) common.OpenAPIDefinition {
|
||||
return common.OpenAPIDefinition{
|
||||
Schema: spec.Schema{
|
||||
|
||||
@@ -1997,6 +1997,11 @@ type ConfigManagementPlugin struct {
|
||||
Generate Command `json:"generate" protobuf:"bytes,3,name=generate"`
|
||||
}
|
||||
|
||||
// HelmOptions holds helm options
|
||||
type HelmOptions struct {
|
||||
ValuesFileSchemes []string `protobuf:"bytes,1,opt,name=valuesFileSchemes"`
|
||||
}
|
||||
|
||||
// KustomizeOptions are options for kustomize to use when building manifests
|
||||
type KustomizeOptions struct {
|
||||
// BuildOptions is a string of build parameters to use when calling `kustomize build`
|
||||
|
||||
@@ -1052,6 +1052,27 @@ func (in *HelmFileParameter) DeepCopy() *HelmFileParameter {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HelmOptions) DeepCopyInto(out *HelmOptions) {
|
||||
*out = *in
|
||||
if in.ValuesFileSchemes != nil {
|
||||
in, out := &in.ValuesFileSchemes, &out.ValuesFileSchemes
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmOptions.
|
||||
func (in *HelmOptions) DeepCopy() *HelmOptions {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HelmOptions)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HelmParameter) DeepCopyInto(out *HelmParameter) {
|
||||
*out = *in
|
||||
|
||||
15
reposerver/apiclient/repository.go
Normal file
15
reposerver/apiclient/repository.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package apiclient
|
||||
|
||||
func (q *ManifestRequest) GetValuesFileSchemes() []string {
|
||||
if q.HelmOptions == nil {
|
||||
return nil
|
||||
}
|
||||
return q.HelmOptions.ValuesFileSchemes
|
||||
}
|
||||
|
||||
func (q *RepoServerAppDetailsQuery) GetValuesFileSchemes() []string {
|
||||
if q.HelmOptions == nil {
|
||||
return nil
|
||||
}
|
||||
return q.HelmOptions.ValuesFileSchemes
|
||||
}
|
||||
@@ -50,6 +50,7 @@ type ManifestRequest struct {
|
||||
VerifySignature bool `protobuf:"varint,16,opt,name=verifySignature,proto3" json:"verifySignature,omitempty"`
|
||||
HelmRepoCreds []*v1alpha1.RepoCreds `protobuf:"bytes,17,rep,name=helmRepoCreds,proto3" json:"helmRepoCreds,omitempty"`
|
||||
NoRevisionCache bool `protobuf:"varint,18,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"`
|
||||
HelmOptions *v1alpha1.HelmOptions `protobuf:"bytes,21,opt,name=helmOptions,proto3" json:"helmOptions,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -193,6 +194,13 @@ func (m *ManifestRequest) GetNoRevisionCache() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *ManifestRequest) GetHelmOptions() *v1alpha1.HelmOptions {
|
||||
if m != nil {
|
||||
return m.HelmOptions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestRepositoryRequest is a query to test repository is valid or not and has valid access.
|
||||
type TestRepositoryRequest struct {
|
||||
Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
|
||||
@@ -595,6 +603,7 @@ type RepoServerAppDetailsQuery struct {
|
||||
AppName string `protobuf:"bytes,5,opt,name=appName,proto3" json:"appName,omitempty"`
|
||||
NoCache bool `protobuf:"varint,6,opt,name=noCache,proto3" json:"noCache,omitempty"`
|
||||
NoRevisionCache bool `protobuf:"varint,7,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"`
|
||||
HelmOptions *v1alpha1.HelmOptions `protobuf:"bytes,10,opt,name=helmOptions,proto3" json:"helmOptions,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -682,6 +691,13 @@ func (m *RepoServerAppDetailsQuery) GetNoRevisionCache() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *RepoServerAppDetailsQuery) GetHelmOptions() *v1alpha1.HelmOptions {
|
||||
if m != nil {
|
||||
return m.HelmOptions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RepoAppDetailsResponse application details
|
||||
type RepoAppDetailsResponse struct {
|
||||
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||
@@ -1367,95 +1383,96 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_dd8723cfcc820480 = []byte{
|
||||
// 1399 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x4b, 0x6f, 0xdb, 0xc6,
|
||||
0x16, 0x36, 0x65, 0xd9, 0xb2, 0x8e, 0x12, 0x5b, 0x9e, 0x3c, 0x2e, 0xaf, 0xae, 0x23, 0x38, 0x04,
|
||||
0x6e, 0xe0, 0x36, 0x0d, 0x85, 0x28, 0x41, 0x1b, 0x24, 0x40, 0x01, 0xd5, 0x49, 0x1c, 0xc0, 0x49,
|
||||
0xec, 0xd2, 0x69, 0x81, 0x16, 0x41, 0x83, 0x31, 0x75, 0x4c, 0x4d, 0x25, 0x91, 0x13, 0x92, 0x52,
|
||||
0xe1, 0x00, 0x5d, 0x16, 0x5d, 0x74, 0xdd, 0xae, 0xfa, 0x5f, 0xba, 0xea, 0x63, 0xd9, 0xfe, 0x83,
|
||||
0x22, 0xbf, 0xa4, 0x98, 0xe1, 0x6b, 0x48, 0xd1, 0xee, 0x42, 0x89, 0xb3, 0xb1, 0x67, 0xce, 0x7b,
|
||||
0xce, 0x9c, 0xf3, 0xcd, 0xa1, 0xe0, 0x9a, 0x8f, 0xdc, 0x0b, 0xd0, 0x9f, 0xa2, 0xdf, 0x91, 0x4b,
|
||||
0x16, 0x7a, 0xfe, 0xb1, 0xb2, 0x34, 0xb9, 0xef, 0x85, 0x1e, 0x81, 0x8c, 0xd2, 0xba, 0xe8, 0x78,
|
||||
0x8e, 0x27, 0xc9, 0x1d, 0xb1, 0x8a, 0x24, 0x5a, 0x1b, 0x8e, 0xe7, 0x39, 0x23, 0xec, 0x50, 0xce,
|
||||
0x3a, 0xd4, 0x75, 0xbd, 0x90, 0x86, 0xcc, 0x73, 0x83, 0x98, 0x6b, 0x0c, 0xef, 0x04, 0x26, 0xf3,
|
||||
0x24, 0xd7, 0xf6, 0x7c, 0xec, 0x4c, 0x6f, 0x76, 0x1c, 0x74, 0xd1, 0xa7, 0x21, 0xf6, 0x63, 0x99,
|
||||
0xc7, 0x0e, 0x0b, 0x07, 0x93, 0x43, 0xd3, 0xf6, 0xc6, 0x1d, 0xea, 0x4b, 0x17, 0x5f, 0xcb, 0xc5,
|
||||
0x0d, 0xbb, 0xdf, 0x99, 0x76, 0x3b, 0x7c, 0xe8, 0x08, 0xfd, 0xa0, 0x43, 0x39, 0x1f, 0x31, 0x5b,
|
||||
0xda, 0xef, 0x4c, 0x6f, 0xd2, 0x11, 0x1f, 0xd0, 0x19, 0x6b, 0xc6, 0x5f, 0x35, 0x58, 0x7b, 0x42,
|
||||
0x5d, 0x76, 0x84, 0x41, 0x68, 0xe1, 0xcb, 0x09, 0x06, 0x21, 0x79, 0x0e, 0x55, 0x71, 0x0e, 0x5d,
|
||||
0xdb, 0xd4, 0xb6, 0x1a, 0xdd, 0x47, 0x66, 0xe6, 0xd0, 0x4c, 0x1c, 0xca, 0xc5, 0x0b, 0xbb, 0x6f,
|
||||
0x4e, 0xbb, 0x26, 0x1f, 0x3a, 0xa6, 0x70, 0x68, 0x2a, 0x0e, 0xcd, 0xc4, 0xa1, 0x69, 0xa5, 0x19,
|
||||
0xb1, 0xa4, 0x55, 0xd2, 0x82, 0x15, 0x1f, 0xa7, 0x2c, 0x60, 0x9e, 0xab, 0x57, 0x36, 0xb5, 0xad,
|
||||
0xba, 0x95, 0xee, 0x89, 0x0e, 0x35, 0xd7, 0xdb, 0xa6, 0xf6, 0x00, 0xf5, 0xc5, 0x4d, 0x6d, 0x6b,
|
||||
0xc5, 0x4a, 0xb6, 0x64, 0x13, 0x1a, 0x94, 0xf3, 0xc7, 0xf4, 0x10, 0x47, 0xbb, 0x78, 0xac, 0x57,
|
||||
0xa5, 0xa2, 0x4a, 0x12, 0xba, 0x94, 0xf3, 0xa7, 0x74, 0x8c, 0xfa, 0x92, 0xe4, 0x26, 0x5b, 0xb2,
|
||||
0x01, 0x75, 0x97, 0x8e, 0x31, 0xe0, 0xd4, 0x46, 0x7d, 0x45, 0xf2, 0x32, 0x02, 0xf9, 0x16, 0xd6,
|
||||
0x95, 0xc0, 0x0f, 0xbc, 0x89, 0x6f, 0xa3, 0x0e, 0xf2, 0xe8, 0x7b, 0xf3, 0x1d, 0xbd, 0x57, 0x34,
|
||||
0x6b, 0xcd, 0x7a, 0x22, 0x5f, 0xc1, 0x92, 0x2c, 0x1a, 0xbd, 0xb1, 0xb9, 0xf8, 0x46, 0xb3, 0x1d,
|
||||
0x99, 0x25, 0x2e, 0xd4, 0xf8, 0x68, 0xe2, 0x30, 0x37, 0xd0, 0xcf, 0x49, 0x0f, 0xcf, 0xe6, 0xf3,
|
||||
0xb0, 0xed, 0xb9, 0x47, 0xcc, 0x79, 0x42, 0x5d, 0xea, 0xe0, 0x18, 0xdd, 0x70, 0x5f, 0x1a, 0xb7,
|
||||
0x12, 0x27, 0xe4, 0x15, 0x34, 0x87, 0x93, 0x20, 0xf4, 0xc6, 0xec, 0x15, 0xee, 0x71, 0x59, 0xdc,
|
||||
0xfa, 0x79, 0x99, 0xcd, 0xa7, 0xf3, 0x39, 0xde, 0x2d, 0x58, 0xb5, 0x66, 0xfc, 0x88, 0x22, 0x19,
|
||||
0x4e, 0x0e, 0xf1, 0x73, 0xf4, 0x65, 0x75, 0xad, 0x46, 0x45, 0xa2, 0x90, 0xa2, 0x32, 0x62, 0xf1,
|
||||
0x2e, 0xd0, 0xd7, 0x36, 0x17, 0xa3, 0x32, 0x4a, 0x49, 0x64, 0x0b, 0xd6, 0xa6, 0xe8, 0xb3, 0xa3,
|
||||
0xe3, 0x03, 0xe6, 0xb8, 0x34, 0x9c, 0xf8, 0xa8, 0x37, 0x65, 0x29, 0x16, 0xc9, 0x64, 0x0c, 0xe7,
|
||||
0x07, 0x38, 0x1a, 0x8b, 0x94, 0x6f, 0xfb, 0xd8, 0x0f, 0xf4, 0x75, 0x99, 0xdf, 0x9d, 0xf9, 0x6f,
|
||||
0x50, 0x9a, 0xb3, 0xf2, 0xd6, 0x45, 0x60, 0xae, 0x67, 0xc5, 0x9d, 0x12, 0xf5, 0x08, 0x89, 0x02,
|
||||
0x2b, 0x90, 0x8d, 0x09, 0x5c, 0x7a, 0x26, 0xdb, 0x39, 0xad, 0x85, 0xb3, 0x68, 0x6c, 0xe3, 0x11,
|
||||
0x5c, 0x2e, 0xba, 0x0d, 0xb8, 0xe7, 0x06, 0x48, 0x4c, 0x20, 0x32, 0x79, 0x0c, 0xfb, 0x19, 0x57,
|
||||
0x46, 0xb1, 0x62, 0x95, 0x70, 0x8c, 0xdf, 0x34, 0x68, 0x66, 0xa0, 0x14, 0x1b, 0xd9, 0x80, 0xfa,
|
||||
0x38, 0xa6, 0x05, 0xba, 0x26, 0x2f, 0x2e, 0x23, 0xe4, 0x7b, 0xbc, 0x52, 0xec, 0xf1, 0xcb, 0xb0,
|
||||
0x1c, 0xa1, 0xb7, 0x84, 0x95, 0xba, 0x15, 0xef, 0x72, 0x58, 0x54, 0x2d, 0x60, 0x51, 0x1b, 0x20,
|
||||
0x90, 0x2d, 0xfa, 0xec, 0x98, 0xa3, 0xbe, 0x2c, 0xb9, 0x0a, 0x85, 0x18, 0x70, 0x2e, 0xaa, 0x08,
|
||||
0x0b, 0x83, 0xc9, 0x28, 0xd4, 0x6b, 0x52, 0x22, 0x47, 0x33, 0x3c, 0x58, 0x7b, 0xcc, 0xc4, 0x19,
|
||||
0x8e, 0x82, 0xb3, 0xb9, 0x83, 0x0f, 0xa1, 0x2a, 0x9c, 0x89, 0x83, 0x1d, 0xfa, 0xd4, 0xb5, 0x07,
|
||||
0x98, 0xe4, 0x2a, 0xdd, 0x13, 0x02, 0xd5, 0x90, 0x3a, 0x81, 0x5e, 0x91, 0x74, 0xb9, 0x36, 0x7e,
|
||||
0xd0, 0xa2, 0x48, 0x7b, 0x9c, 0x07, 0xef, 0xfc, 0x19, 0x30, 0x26, 0x50, 0xeb, 0x71, 0x2e, 0xe2,
|
||||
0x21, 0x37, 0xa1, 0x4a, 0x39, 0x8f, 0x0e, 0xd1, 0xe8, 0x5e, 0x31, 0x95, 0x27, 0x37, 0x16, 0x11,
|
||||
0xff, 0x83, 0x07, 0x6e, 0x28, 0x2c, 0x0b, 0xd1, 0xd6, 0x47, 0x50, 0x4f, 0x49, 0xa4, 0x09, 0x8b,
|
||||
0x43, 0x8c, 0x6a, 0xad, 0x6e, 0x89, 0x25, 0xb9, 0x08, 0x4b, 0x53, 0x3a, 0x9a, 0x24, 0x55, 0x12,
|
||||
0x6d, 0xee, 0x56, 0xee, 0x68, 0xc6, 0xcf, 0x55, 0xf8, 0xaf, 0x88, 0xf3, 0x40, 0x16, 0x47, 0x8f,
|
||||
0xf3, 0xfb, 0x18, 0x52, 0x36, 0x0a, 0x3e, 0x9d, 0xa0, 0x7f, 0xfc, 0x96, 0xd3, 0xe1, 0xc0, 0x72,
|
||||
0x54, 0x5b, 0x32, 0xac, 0xb7, 0xf0, 0xf4, 0xc4, 0xe6, 0xb3, 0xf7, 0x66, 0xf1, 0xed, 0xbc, 0x37,
|
||||
0x65, 0xf8, 0x5f, 0x3d, 0x23, 0xfc, 0x3f, 0x79, 0x04, 0x50, 0x06, 0x8b, 0xe5, 0xfc, 0x60, 0x51,
|
||||
0x02, 0xab, 0xb5, 0x72, 0x58, 0xfd, 0xbe, 0x02, 0x97, 0xc5, 0x79, 0xb3, 0xc2, 0x48, 0xb1, 0x49,
|
||||
0xb4, 0x94, 0x40, 0x89, 0xa8, 0xcc, 0xe4, 0x9a, 0xdc, 0x86, 0xda, 0x30, 0xf0, 0x5c, 0x17, 0xc3,
|
||||
0xf8, 0x4a, 0x5b, 0x6a, 0xf1, 0xee, 0x46, 0xac, 0x1e, 0xe7, 0x07, 0x1c, 0x6d, 0x2b, 0x11, 0x25,
|
||||
0xd7, 0xa1, 0x2a, 0x60, 0x5f, 0xe2, 0x54, 0xa3, 0xfb, 0x1f, 0x55, 0xe5, 0x11, 0x8e, 0xc6, 0x89,
|
||||
0xbc, 0x14, 0x22, 0x77, 0xa1, 0x9e, 0xe6, 0x20, 0x4e, 0xf2, 0x46, 0xce, 0x49, 0xc2, 0x4c, 0xd4,
|
||||
0x32, 0x71, 0xa1, 0xdb, 0x67, 0x3e, 0xda, 0x12, 0x8a, 0x97, 0x66, 0x75, 0xef, 0x27, 0xcc, 0x54,
|
||||
0x37, 0x15, 0x37, 0x7e, 0xd5, 0xe0, 0x6a, 0xd6, 0x28, 0x49, 0x96, 0x9e, 0x60, 0x48, 0xfb, 0x34,
|
||||
0xa4, 0xef, 0x7e, 0x8c, 0xbc, 0x06, 0xab, 0xf6, 0x00, 0xed, 0x61, 0xf6, 0x84, 0x47, 0xd3, 0x64,
|
||||
0x81, 0x6a, 0xfc, 0x5e, 0x81, 0xd5, 0xfc, 0x45, 0x88, 0x9b, 0x14, 0xcf, 0x46, 0x72, 0x93, 0x62,
|
||||
0x4d, 0xf6, 0xe1, 0x1c, 0xba, 0x53, 0xe6, 0x7b, 0xae, 0x18, 0x78, 0x92, 0xce, 0xf9, 0xe0, 0xe4,
|
||||
0xeb, 0x34, 0x1f, 0x28, 0xe2, 0x11, 0x34, 0xe5, 0x2c, 0x10, 0x17, 0x80, 0x53, 0x9f, 0x8e, 0x31,
|
||||
0x44, 0x5f, 0xb4, 0xc7, 0xe2, 0x1b, 0x68, 0x8f, 0x28, 0x82, 0xfd, 0xc4, 0xac, 0xa5, 0x78, 0x68,
|
||||
0xbd, 0x80, 0xf5, 0x99, 0x90, 0x4a, 0xa0, 0xf1, 0xb6, 0x0a, 0x8d, 0x8d, 0x6e, 0xbb, 0xe4, 0x84,
|
||||
0x8a, 0x19, 0x15, 0x3a, 0x7f, 0xa9, 0x40, 0x43, 0xa9, 0xcf, 0xd2, 0x34, 0xb6, 0x01, 0xa4, 0xc2,
|
||||
0x43, 0x36, 0xc2, 0x28, 0x89, 0x75, 0x4b, 0xa1, 0x90, 0x61, 0x49, 0x52, 0x76, 0xe7, 0x4b, 0x8a,
|
||||
0x08, 0xa9, 0x34, 0x23, 0x62, 0x22, 0x90, 0xae, 0x83, 0x18, 0x29, 0xe2, 0x1d, 0xf9, 0x06, 0x56,
|
||||
0x8f, 0xd8, 0x08, 0xf7, 0xb3, 0x40, 0x96, 0x65, 0x20, 0x7b, 0xf3, 0x07, 0xf2, 0x50, 0xb5, 0x6b,
|
||||
0x15, 0xdc, 0x18, 0xef, 0x43, 0xb3, 0xd8, 0xae, 0x22, 0x48, 0x36, 0xa6, 0x4e, 0x9a, 0xad, 0x78,
|
||||
0x67, 0xfc, 0xa8, 0x01, 0x99, 0xbd, 0x8f, 0x93, 0x92, 0x3e, 0xbc, 0x13, 0x24, 0x13, 0x71, 0xd4,
|
||||
0x28, 0x0a, 0x85, 0xec, 0x42, 0xa3, 0x8f, 0x41, 0xc8, 0x5c, 0x19, 0x70, 0x0c, 0x22, 0xef, 0x9d,
|
||||
0x7e, 0xf1, 0xf7, 0x33, 0x05, 0x4b, 0xd5, 0x36, 0x3e, 0x83, 0x2b, 0xa7, 0x4a, 0x2b, 0x73, 0x98,
|
||||
0x96, 0x9b, 0xc3, 0x4e, 0x9d, 0xde, 0x0c, 0x02, 0xcd, 0x22, 0x1a, 0x19, 0x2f, 0x61, 0x5d, 0xe4,
|
||||
0x74, 0x7b, 0x40, 0xfd, 0xf0, 0x8c, 0x66, 0xab, 0x7b, 0x50, 0x4f, 0x5d, 0x96, 0xe6, 0xba, 0x05,
|
||||
0x2b, 0xd3, 0xe4, 0xcb, 0x22, 0x1a, 0xae, 0xd2, 0xbd, 0xd1, 0x03, 0xa2, 0xc6, 0x1b, 0xbf, 0x1b,
|
||||
0xd7, 0x61, 0x89, 0x85, 0x38, 0x4e, 0xc6, 0x9b, 0x4b, 0x45, 0xb8, 0x97, 0xe2, 0x56, 0x24, 0xd3,
|
||||
0xfd, 0x6e, 0x09, 0xd6, 0x33, 0xd4, 0x15, 0x7f, 0x99, 0x8d, 0x64, 0x0f, 0x9a, 0x3b, 0xf1, 0x37,
|
||||
0x7d, 0x32, 0x32, 0x93, 0xff, 0xa9, 0x76, 0x0a, 0x5f, 0xf7, 0xad, 0x8d, 0x72, 0x66, 0x14, 0x91,
|
||||
0xb1, 0x40, 0xbe, 0x80, 0xd5, 0xfc, 0x18, 0x4f, 0xae, 0xaa, 0x1a, 0xa5, 0x5f, 0x16, 0x2d, 0xe3,
|
||||
0x34, 0x91, 0xd4, 0xf4, 0x3d, 0x58, 0x49, 0xc6, 0xe1, 0x7c, 0x8c, 0x85, 0x21, 0xb9, 0xd5, 0x54,
|
||||
0x99, 0x82, 0x61, 0x2c, 0x90, 0x8f, 0x23, 0x65, 0x31, 0xda, 0xcd, 0x2a, 0x2b, 0x73, 0x6b, 0xeb,
|
||||
0x42, 0xc9, 0x90, 0x68, 0x2c, 0x90, 0xe7, 0x70, 0x7e, 0x47, 0x22, 0x74, 0xfc, 0x78, 0x93, 0xff,
|
||||
0xe7, 0x9d, 0x9c, 0x30, 0xf7, 0xe5, 0x8f, 0x56, 0xfe, 0xfe, 0x1b, 0x0b, 0xe4, 0x27, 0x0d, 0x2e,
|
||||
0xec, 0x60, 0x58, 0x7c, 0x0b, 0xc9, 0x8d, 0x72, 0x27, 0x27, 0xbc, 0x99, 0xad, 0xa7, 0xf3, 0xd6,
|
||||
0x6c, 0xde, 0xac, 0xb1, 0x40, 0xf6, 0xe5, 0xb1, 0xb3, 0xda, 0x23, 0x57, 0x4a, 0x8b, 0x2c, 0xcd,
|
||||
0x5e, 0xfb, 0x24, 0x76, 0x72, 0xd4, 0x4f, 0x7a, 0x7f, 0xbc, 0x6e, 0x6b, 0x7f, 0xbe, 0x6e, 0x6b,
|
||||
0x7f, 0xbf, 0x6e, 0x6b, 0x5f, 0xde, 0xfa, 0x97, 0x9f, 0xa3, 0x94, 0x5f, 0xce, 0x28, 0x67, 0xf6,
|
||||
0x88, 0xa1, 0x1b, 0x1e, 0x2e, 0xcb, 0x1f, 0x9f, 0x6e, 0xfd, 0x13, 0x00, 0x00, 0xff, 0xff, 0x9e,
|
||||
0x66, 0xb6, 0xa2, 0x58, 0x13, 0x00, 0x00,
|
||||
// 1417 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x5b, 0x6f, 0x1b, 0x45,
|
||||
0x14, 0xce, 0x3a, 0x76, 0x62, 0x1f, 0xb7, 0x89, 0x33, 0xbd, 0xb0, 0x98, 0xd4, 0x4a, 0x57, 0xa2,
|
||||
0x0a, 0x94, 0xae, 0x55, 0xb7, 0x82, 0xaa, 0x95, 0x90, 0x4c, 0xda, 0xa6, 0x28, 0x6d, 0x13, 0x36,
|
||||
0x05, 0x09, 0x54, 0x51, 0x4d, 0xd6, 0x93, 0xf5, 0x60, 0x7b, 0x77, 0xba, 0xb3, 0x36, 0x4a, 0x25,
|
||||
0x1e, 0x11, 0x42, 0x3c, 0xc3, 0xcf, 0x81, 0x27, 0x2e, 0x8f, 0xfc, 0x04, 0x94, 0x5f, 0x82, 0x66,
|
||||
0xf6, 0x36, 0xbb, 0x5e, 0x07, 0x24, 0x37, 0xe9, 0x4b, 0x32, 0x73, 0xee, 0x73, 0xe6, 0xcc, 0x77,
|
||||
0x8e, 0x17, 0xae, 0xf9, 0x84, 0x79, 0x9c, 0xf8, 0x13, 0xe2, 0xb7, 0xe5, 0x92, 0x06, 0x9e, 0x7f,
|
||||
0xa4, 0x2c, 0x4d, 0xe6, 0x7b, 0x81, 0x87, 0x20, 0xa5, 0x34, 0x2f, 0x3a, 0x9e, 0xe3, 0x49, 0x72,
|
||||
0x5b, 0xac, 0x42, 0x89, 0xe6, 0xba, 0xe3, 0x79, 0xce, 0x90, 0xb4, 0x31, 0xa3, 0x6d, 0xec, 0xba,
|
||||
0x5e, 0x80, 0x03, 0xea, 0xb9, 0x3c, 0xe2, 0x1a, 0x83, 0x3b, 0xdc, 0xa4, 0x9e, 0xe4, 0xda, 0x9e,
|
||||
0x4f, 0xda, 0x93, 0x9b, 0x6d, 0x87, 0xb8, 0xc4, 0xc7, 0x01, 0xe9, 0x45, 0x32, 0x8f, 0x1d, 0x1a,
|
||||
0xf4, 0xc7, 0x07, 0xa6, 0xed, 0x8d, 0xda, 0xd8, 0x97, 0x2e, 0xbe, 0x91, 0x8b, 0x1b, 0x76, 0xaf,
|
||||
0x3d, 0xe9, 0xb4, 0xd9, 0xc0, 0x11, 0xfa, 0xbc, 0x8d, 0x19, 0x1b, 0x52, 0x5b, 0xda, 0x6f, 0x4f,
|
||||
0x6e, 0xe2, 0x21, 0xeb, 0xe3, 0x29, 0x6b, 0xc6, 0xaf, 0x55, 0x58, 0x7d, 0x82, 0x5d, 0x7a, 0x48,
|
||||
0x78, 0x60, 0x91, 0x97, 0x63, 0xc2, 0x03, 0xf4, 0x1c, 0xca, 0xe2, 0x1c, 0xba, 0xb6, 0xa1, 0x6d,
|
||||
0xd6, 0x3b, 0x8f, 0xcc, 0xd4, 0xa1, 0x19, 0x3b, 0x94, 0x8b, 0x17, 0x76, 0xcf, 0x9c, 0x74, 0x4c,
|
||||
0x36, 0x70, 0x4c, 0xe1, 0xd0, 0x54, 0x1c, 0x9a, 0xb1, 0x43, 0xd3, 0x4a, 0x32, 0x62, 0x49, 0xab,
|
||||
0xa8, 0x09, 0x55, 0x9f, 0x4c, 0x28, 0xa7, 0x9e, 0xab, 0x97, 0x36, 0xb4, 0xcd, 0x9a, 0x95, 0xec,
|
||||
0x91, 0x0e, 0xcb, 0xae, 0xb7, 0x85, 0xed, 0x3e, 0xd1, 0x17, 0x37, 0xb4, 0xcd, 0xaa, 0x15, 0x6f,
|
||||
0xd1, 0x06, 0xd4, 0x31, 0x63, 0x8f, 0xf1, 0x01, 0x19, 0xee, 0x90, 0x23, 0xbd, 0x2c, 0x15, 0x55,
|
||||
0x92, 0xd0, 0xc5, 0x8c, 0x3d, 0xc5, 0x23, 0xa2, 0x57, 0x24, 0x37, 0xde, 0xa2, 0x75, 0xa8, 0xb9,
|
||||
0x78, 0x44, 0x38, 0xc3, 0x36, 0xd1, 0xab, 0x92, 0x97, 0x12, 0xd0, 0x77, 0xb0, 0xa6, 0x04, 0xbe,
|
||||
0xef, 0x8d, 0x7d, 0x9b, 0xe8, 0x20, 0x8f, 0xbe, 0x3b, 0xdf, 0xd1, 0xbb, 0x79, 0xb3, 0xd6, 0xb4,
|
||||
0x27, 0xf4, 0x35, 0x54, 0x64, 0xd1, 0xe8, 0xf5, 0x8d, 0xc5, 0xd7, 0x9a, 0xed, 0xd0, 0x2c, 0x72,
|
||||
0x61, 0x99, 0x0d, 0xc7, 0x0e, 0x75, 0xb9, 0x7e, 0x4e, 0x7a, 0x78, 0x36, 0x9f, 0x87, 0x2d, 0xcf,
|
||||
0x3d, 0xa4, 0xce, 0x13, 0xec, 0x62, 0x87, 0x8c, 0x88, 0x1b, 0xec, 0x49, 0xe3, 0x56, 0xec, 0x04,
|
||||
0xbd, 0x82, 0xc6, 0x60, 0xcc, 0x03, 0x6f, 0x44, 0x5f, 0x91, 0x5d, 0x26, 0x8b, 0x5b, 0x3f, 0x2f,
|
||||
0xb3, 0xf9, 0x74, 0x3e, 0xc7, 0x3b, 0x39, 0xab, 0xd6, 0x94, 0x1f, 0x51, 0x24, 0x83, 0xf1, 0x01,
|
||||
0xf9, 0x82, 0xf8, 0xb2, 0xba, 0x56, 0xc2, 0x22, 0x51, 0x48, 0x61, 0x19, 0xd1, 0x68, 0xc7, 0xf5,
|
||||
0xd5, 0x8d, 0xc5, 0xb0, 0x8c, 0x12, 0x12, 0xda, 0x84, 0xd5, 0x09, 0xf1, 0xe9, 0xe1, 0xd1, 0x3e,
|
||||
0x75, 0x5c, 0x1c, 0x8c, 0x7d, 0xa2, 0x37, 0x64, 0x29, 0xe6, 0xc9, 0x68, 0x04, 0xe7, 0xfb, 0x64,
|
||||
0x38, 0x12, 0x29, 0xdf, 0xf2, 0x49, 0x8f, 0xeb, 0x6b, 0x32, 0xbf, 0xdb, 0xf3, 0xdf, 0xa0, 0x34,
|
||||
0x67, 0x65, 0xad, 0x8b, 0xc0, 0x5c, 0xcf, 0x8a, 0x5e, 0x4a, 0xf8, 0x46, 0x50, 0x18, 0x58, 0x8e,
|
||||
0x8c, 0x06, 0x50, 0x17, 0xaa, 0x71, 0xf6, 0x2f, 0xc9, 0xec, 0x7f, 0x3a, 0x5f, 0x58, 0x8f, 0x52,
|
||||
0x83, 0x96, 0x6a, 0xdd, 0x18, 0xc3, 0xa5, 0x67, 0x12, 0x3b, 0x92, 0xc2, 0x3b, 0x0b, 0x14, 0x31,
|
||||
0x1e, 0xc1, 0xe5, 0xbc, 0x5b, 0xce, 0x3c, 0x97, 0x13, 0x64, 0x02, 0x92, 0x37, 0x45, 0x49, 0x2f,
|
||||
0xe5, 0xca, 0x28, 0xaa, 0x56, 0x01, 0xc7, 0xf8, 0x43, 0x83, 0x46, 0x8a, 0x80, 0x91, 0x91, 0x75,
|
||||
0xa8, 0x8d, 0x22, 0x1a, 0xd7, 0x35, 0x59, 0x25, 0x29, 0x21, 0x0b, 0x28, 0xa5, 0x3c, 0xa0, 0x5c,
|
||||
0x86, 0xa5, 0xb0, 0x55, 0x48, 0x0c, 0xab, 0x59, 0xd1, 0x2e, 0x03, 0x7c, 0xe5, 0x1c, 0xf0, 0xb5,
|
||||
0x00, 0xb8, 0xc4, 0x83, 0x67, 0x47, 0x8c, 0xe8, 0x4b, 0x92, 0xab, 0x50, 0x90, 0x01, 0xe7, 0xc2,
|
||||
0xf2, 0xb3, 0x08, 0x1f, 0x0f, 0x03, 0x7d, 0x59, 0x4a, 0x64, 0x68, 0x86, 0x07, 0xab, 0x8f, 0xa9,
|
||||
0x38, 0xc3, 0x21, 0x3f, 0x9b, 0x3b, 0xf8, 0x10, 0xca, 0xc2, 0x99, 0x38, 0xd8, 0x81, 0x8f, 0x5d,
|
||||
0xbb, 0x4f, 0xe2, 0x5c, 0x25, 0x7b, 0x84, 0xa0, 0x1c, 0x60, 0x87, 0xeb, 0x25, 0x49, 0x97, 0x6b,
|
||||
0xe3, 0x27, 0x2d, 0x8c, 0xb4, 0xcb, 0x18, 0x7f, 0xe3, 0x3d, 0xc7, 0x18, 0xc3, 0x72, 0x97, 0x31,
|
||||
0x11, 0x0f, 0xba, 0x09, 0x65, 0xcc, 0x58, 0x78, 0x88, 0x7a, 0xe7, 0x8a, 0xa9, 0xf4, 0xf7, 0x48,
|
||||
0x44, 0xfc, 0xe7, 0x0f, 0xdc, 0x40, 0x58, 0x16, 0xa2, 0xcd, 0x8f, 0xa0, 0x96, 0x90, 0x50, 0x03,
|
||||
0x16, 0x07, 0x24, 0xac, 0xb5, 0x9a, 0x25, 0x96, 0xe8, 0x22, 0x54, 0x26, 0x78, 0x38, 0x8e, 0xab,
|
||||
0x24, 0xdc, 0xdc, 0x2d, 0xdd, 0xd1, 0x8c, 0x1f, 0x2b, 0xf0, 0xb6, 0x88, 0x73, 0x5f, 0x16, 0x47,
|
||||
0x97, 0xb1, 0xfb, 0x24, 0xc0, 0x74, 0xc8, 0x3f, 0x1b, 0x13, 0xff, 0xe8, 0x94, 0xd3, 0xe1, 0xc0,
|
||||
0x52, 0x58, 0x5b, 0x32, 0xac, 0x53, 0xe8, 0x73, 0x91, 0xf9, 0xb4, 0xb9, 0x2d, 0x9e, 0x4e, 0x73,
|
||||
0x2b, 0x6a, 0x36, 0xe5, 0x33, 0x6a, 0x36, 0xb3, 0xe7, 0x0d, 0x65, 0x8a, 0x59, 0xca, 0x4e, 0x31,
|
||||
0x05, 0x18, 0xbe, 0xfc, 0xbf, 0x30, 0x1c, 0x4e, 0x15, 0xc3, 0x7f, 0x28, 0xc1, 0x65, 0x91, 0xdc,
|
||||
0xb4, 0x0a, 0x13, 0x20, 0x14, 0xef, 0x57, 0x40, 0x52, 0x58, 0xd3, 0x72, 0x8d, 0x6e, 0xc3, 0xf2,
|
||||
0x80, 0x7b, 0xae, 0x4b, 0x82, 0xa8, 0x7e, 0x9a, 0xea, 0x4b, 0xd9, 0x09, 0x59, 0x5d, 0xc6, 0xf6,
|
||||
0x19, 0xb1, 0xad, 0x58, 0x14, 0x5d, 0x87, 0xb2, 0xf0, 0x29, 0x41, 0xb1, 0xde, 0x79, 0x4b, 0x55,
|
||||
0x11, 0x81, 0xc5, 0xf2, 0x52, 0x08, 0xdd, 0x85, 0x5a, 0x92, 0xf0, 0xe8, 0x46, 0xd7, 0x33, 0x4e,
|
||||
0x62, 0x66, 0xac, 0x96, 0x8a, 0x0b, 0xdd, 0x1e, 0xf5, 0x89, 0x2d, 0x71, 0xbf, 0x32, 0xad, 0x7b,
|
||||
0x3f, 0x66, 0x26, 0xba, 0x89, 0xb8, 0xf1, 0xbb, 0x06, 0x57, 0xd3, 0x57, 0x19, 0x5f, 0xc9, 0x13,
|
||||
0x12, 0xe0, 0x1e, 0x0e, 0xf0, 0x9b, 0x1f, 0x90, 0xaf, 0xc1, 0x8a, 0xdd, 0x27, 0xf6, 0x20, 0x1d,
|
||||
0x4e, 0xc2, 0x39, 0x39, 0x47, 0x35, 0xfe, 0x2c, 0xc1, 0x4a, 0xf6, 0x22, 0xc4, 0x4d, 0x8a, 0x1e,
|
||||
0x15, 0xdf, 0xa4, 0x58, 0xa3, 0x3d, 0x38, 0x47, 0xdc, 0x09, 0xf5, 0x3d, 0x57, 0x8c, 0x72, 0xf1,
|
||||
0x33, 0xfd, 0x60, 0xf6, 0x75, 0x9a, 0x0f, 0x14, 0xf1, 0x10, 0x07, 0x33, 0x16, 0x90, 0x0b, 0xc0,
|
||||
0xb0, 0x8f, 0x47, 0x24, 0x20, 0xbe, 0x78, 0x8b, 0x8b, 0xaf, 0xe1, 0x2d, 0x86, 0x11, 0xec, 0xc5,
|
||||
0x66, 0x2d, 0xc5, 0x43, 0xf3, 0x05, 0xac, 0x4d, 0x85, 0x54, 0x80, 0xc3, 0xb7, 0x55, 0x1c, 0xae,
|
||||
0x77, 0x5a, 0x05, 0x27, 0x54, 0xcc, 0xa8, 0x38, 0xfd, 0x5b, 0x09, 0xea, 0x4a, 0x7d, 0x16, 0xa6,
|
||||
0xb1, 0x05, 0x20, 0x15, 0x1e, 0xd2, 0x21, 0x09, 0x93, 0x58, 0xb3, 0x14, 0x0a, 0x1a, 0x14, 0x24,
|
||||
0x65, 0x67, 0xfe, 0xb7, 0x5c, 0x98, 0x11, 0x31, 0x7e, 0x48, 0xd7, 0x3c, 0x82, 0xa5, 0x68, 0x87,
|
||||
0xbe, 0x85, 0x95, 0x43, 0x3a, 0x24, 0x7b, 0x69, 0x20, 0x4b, 0x32, 0x90, 0xdd, 0xf9, 0x03, 0x79,
|
||||
0xa8, 0xda, 0xb5, 0x72, 0x6e, 0x8c, 0xf7, 0xa1, 0x91, 0x7f, 0xae, 0x22, 0x48, 0x3a, 0xc2, 0x4e,
|
||||
0x92, 0xad, 0x68, 0x67, 0xfc, 0xac, 0x01, 0x9a, 0xbe, 0x8f, 0x59, 0x49, 0x1f, 0xdc, 0xe1, 0xf1,
|
||||
0xac, 0x1f, 0x3e, 0x14, 0x85, 0x82, 0x76, 0xa0, 0xde, 0x23, 0x3c, 0xa0, 0xae, 0x0c, 0x38, 0x02,
|
||||
0x91, 0xf7, 0x4e, 0xbe, 0xf8, 0xfb, 0xa9, 0x82, 0xa5, 0x6a, 0x1b, 0x9f, 0xc3, 0x95, 0x13, 0xa5,
|
||||
0x95, 0xa1, 0x4f, 0xcb, 0x0c, 0x7d, 0x27, 0x8e, 0x8a, 0x06, 0x82, 0x46, 0x1e, 0x8d, 0x8c, 0x97,
|
||||
0xb0, 0x26, 0x72, 0xba, 0xd5, 0xc7, 0x7e, 0x70, 0x46, 0x83, 0xdc, 0x3d, 0xa8, 0x25, 0x2e, 0x0b,
|
||||
0x73, 0xdd, 0x84, 0xea, 0x24, 0xfe, 0xcd, 0x14, 0x4e, 0x72, 0xc9, 0xde, 0xe8, 0x02, 0x52, 0xe3,
|
||||
0x8d, 0xfa, 0xc6, 0x75, 0xa8, 0xd0, 0x80, 0x8c, 0xe2, 0x59, 0xea, 0x52, 0x1e, 0xee, 0xa5, 0xb8,
|
||||
0x15, 0xca, 0x74, 0xbe, 0xaf, 0xc0, 0x5a, 0x8a, 0xba, 0xe2, 0x2f, 0xb5, 0x09, 0xda, 0x85, 0xc6,
|
||||
0x76, 0xf4, 0xb5, 0x22, 0x9e, 0xcf, 0xd1, 0x3b, 0xaa, 0x9d, 0xdc, 0x77, 0x8b, 0xe6, 0x7a, 0x31,
|
||||
0x33, 0x8c, 0xc8, 0x58, 0x40, 0x5f, 0xc2, 0x4a, 0xf6, 0x37, 0x03, 0xba, 0xaa, 0x6a, 0x14, 0xfe,
|
||||
0x8c, 0x69, 0x1a, 0x27, 0x89, 0x24, 0xa6, 0xef, 0x41, 0x35, 0x9e, 0xbd, 0xb3, 0x31, 0xe6, 0x26,
|
||||
0xf2, 0x66, 0x43, 0x65, 0x0a, 0x86, 0xb1, 0x80, 0x3e, 0x0e, 0x95, 0xc5, 0x1c, 0x39, 0xad, 0xac,
|
||||
0x0c, 0xc9, 0xcd, 0x0b, 0x05, 0x13, 0xa9, 0xb1, 0x80, 0x9e, 0xc3, 0xf9, 0x6d, 0x89, 0xd0, 0x51,
|
||||
0xf3, 0x46, 0xef, 0x66, 0x9d, 0xcc, 0x18, 0x32, 0xb3, 0x47, 0x2b, 0xee, 0xff, 0xc6, 0x02, 0xfa,
|
||||
0x45, 0x83, 0x0b, 0xdb, 0x24, 0xc8, 0xf7, 0x42, 0x74, 0xa3, 0xd8, 0xc9, 0x8c, 0x9e, 0xd9, 0x7c,
|
||||
0x3a, 0x6f, 0xcd, 0x66, 0xcd, 0x1a, 0x0b, 0x68, 0x4f, 0x1e, 0x3b, 0xad, 0x3d, 0x74, 0xa5, 0xb0,
|
||||
0xc8, 0x92, 0xec, 0xb5, 0x66, 0xb1, 0xe3, 0xa3, 0x7e, 0xd2, 0xfd, 0xeb, 0xb8, 0xa5, 0xfd, 0x7d,
|
||||
0xdc, 0xd2, 0xfe, 0x39, 0x6e, 0x69, 0x5f, 0xdd, 0xfa, 0x8f, 0x0f, 0x6d, 0xca, 0x37, 0x41, 0xcc,
|
||||
0xa8, 0x3d, 0xa4, 0xc4, 0x0d, 0x0e, 0x96, 0xe4, 0x67, 0xb5, 0x5b, 0xff, 0x06, 0x00, 0x00, 0xff,
|
||||
0xff, 0x44, 0x52, 0x29, 0xd7, 0x32, 0x14, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -1792,6 +1809,20 @@ func (m *ManifestRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if m.HelmOptions != nil {
|
||||
{
|
||||
size, err := m.HelmOptions.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintRepository(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0xaa
|
||||
}
|
||||
if m.NoRevisionCache {
|
||||
i--
|
||||
if m.NoRevisionCache {
|
||||
@@ -2300,6 +2331,18 @@ func (m *RepoServerAppDetailsQuery) MarshalToSizedBuffer(dAtA []byte) (int, erro
|
||||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if m.HelmOptions != nil {
|
||||
{
|
||||
size, err := m.HelmOptions.MarshalToSizedBuffer(dAtA[:i])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i -= size
|
||||
i = encodeVarintRepository(dAtA, i, uint64(size))
|
||||
}
|
||||
i--
|
||||
dAtA[i] = 0x52
|
||||
}
|
||||
if m.NoRevisionCache {
|
||||
i--
|
||||
if m.NoRevisionCache {
|
||||
@@ -3032,6 +3075,10 @@ func (m *ManifestRequest) Size() (n int) {
|
||||
if m.NoRevisionCache {
|
||||
n += 3
|
||||
}
|
||||
if m.HelmOptions != nil {
|
||||
l = m.HelmOptions.Size()
|
||||
n += 2 + l + sovRepository(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
@@ -3221,6 +3268,10 @@ func (m *RepoServerAppDetailsQuery) Size() (n int) {
|
||||
if m.NoRevisionCache {
|
||||
n += 2
|
||||
}
|
||||
if m.HelmOptions != nil {
|
||||
l = m.HelmOptions.Size()
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
@@ -3982,6 +4033,42 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
}
|
||||
m.NoRevisionCache = bool(v != 0)
|
||||
case 21:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field HelmOptions", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.HelmOptions == nil {
|
||||
m.HelmOptions = &v1alpha1.HelmOptions{}
|
||||
}
|
||||
if err := m.HelmOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipRepository(dAtA[iNdEx:])
|
||||
@@ -5147,6 +5234,42 @@ func (m *RepoServerAppDetailsQuery) Unmarshal(dAtA []byte) error {
|
||||
}
|
||||
}
|
||||
m.NoRevisionCache = bool(v != 0)
|
||||
case 10:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field HelmOptions", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowRepository
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthRepository
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.HelmOptions == nil {
|
||||
m.HelmOptions = &v1alpha1.HelmOptions{}
|
||||
}
|
||||
if err := m.HelmOptions.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipRepository(dAtA[iNdEx:])
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
goio "io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -16,6 +17,12 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
kubeyaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/util/io/files"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/TomOnTime/utfutil"
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
@@ -24,6 +31,7 @@ import (
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/google/go-jsonnet"
|
||||
"github.com/google/uuid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -46,10 +54,10 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/util/gpg"
|
||||
"github.com/argoproj/argo-cd/v2/util/helm"
|
||||
"github.com/argoproj/argo-cd/v2/util/io"
|
||||
pathutil "github.com/argoproj/argo-cd/v2/util/io/path"
|
||||
"github.com/argoproj/argo-cd/v2/util/ksonnet"
|
||||
argokube "github.com/argoproj/argo-cd/v2/util/kube"
|
||||
"github.com/argoproj/argo-cd/v2/util/kustomize"
|
||||
"github.com/argoproj/argo-cd/v2/util/security"
|
||||
"github.com/argoproj/argo-cd/v2/util/text"
|
||||
)
|
||||
|
||||
@@ -62,6 +70,8 @@ const (
|
||||
ociPrefix = "oci://"
|
||||
)
|
||||
|
||||
var ErrExceededMaxCombinedManifestFileSize = errors.New("exceeded max combined manifest file size")
|
||||
|
||||
// Service implements ManifestService interface
|
||||
type Service struct {
|
||||
repoLock *repositoryLock
|
||||
@@ -80,6 +90,7 @@ type RepoServerInitConstants struct {
|
||||
PauseGenerationAfterFailedGenerationAttempts int
|
||||
PauseGenerationOnFailureForMinutes int
|
||||
PauseGenerationOnFailureForRequests int
|
||||
MaxCombinedDirectoryManifestsSize resource.Quantity
|
||||
}
|
||||
|
||||
// NewService returns a new instance of the Manifest service
|
||||
@@ -319,7 +330,7 @@ func (s *Service) runManifestGen(repoRoot, commitSHA, cacheKey string, ctxSrc op
|
||||
var manifestGenResult *apiclient.ManifestResponse
|
||||
ctx, err := ctxSrc()
|
||||
if err == nil {
|
||||
manifestGenResult, err = GenerateManifests(ctx.appPath, repoRoot, commitSHA, q, false)
|
||||
manifestGenResult, err = GenerateManifests(ctx.appPath, repoRoot, commitSHA, q, false, s.initConstants.MaxCombinedDirectoryManifestsSize)
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -489,8 +500,9 @@ func getHelmDependencyRepos(appPath string) ([]*v1alpha1.Repository, error) {
|
||||
for _, r := range d.Dependencies {
|
||||
if u, err := url.Parse(r.Repository); err == nil && (u.Scheme == "https" || u.Scheme == "oci") {
|
||||
repo := &v1alpha1.Repository{
|
||||
Repo: r.Repository,
|
||||
Name: r.Repository,
|
||||
Repo: r.Repository,
|
||||
Name: r.Repository,
|
||||
EnableOCI: u.Scheme == "oci",
|
||||
}
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
@@ -557,7 +569,7 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
|
||||
APIVersions: q.ApiVersions,
|
||||
Set: map[string]string{},
|
||||
SetString: map[string]string{},
|
||||
SetFile: map[string]string{},
|
||||
SetFile: map[string]pathutil.ResolvedFilePath{},
|
||||
}
|
||||
|
||||
appHelm := q.ApplicationSource.Helm
|
||||
@@ -571,46 +583,28 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
|
||||
}
|
||||
|
||||
for _, val := range appHelm.ValueFiles {
|
||||
// If val is not a URL, run it against the directory enforcer. If it is a URL, use it without checking
|
||||
if _, err := url.ParseRequestURI(val); err != nil {
|
||||
|
||||
// Ensure that the repo root provided is absolute
|
||||
absRepoPath, err := filepath.Abs(repoRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the path to the file is relative, join it with the current working directory (appPath)
|
||||
path := val
|
||||
if !filepath.IsAbs(path) {
|
||||
absWorkDir, err := filepath.Abs(appPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path = filepath.Join(absWorkDir, path)
|
||||
}
|
||||
|
||||
_, err = security.EnforceToCurrentRoot(absRepoPath, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
templateOpts.Values = append(templateOpts.Values, val)
|
||||
}
|
||||
|
||||
if appHelm.Values != "" {
|
||||
file, err := ioutil.TempFile("", "values-*.yaml")
|
||||
// This will resolve val to an absolute path (or an URL)
|
||||
path, _, err := pathutil.ResolveFilePath(appPath, repoRoot, val, q.GetValuesFileSchemes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := file.Name()
|
||||
|
||||
templateOpts.Values = append(templateOpts.Values, path)
|
||||
}
|
||||
|
||||
if appHelm.Values != "" {
|
||||
rand, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := path.Join(os.TempDir(), rand.String())
|
||||
defer func() { _ = os.RemoveAll(p) }()
|
||||
err = ioutil.WriteFile(p, []byte(appHelm.Values), 0644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
templateOpts.Values = append(templateOpts.Values, p)
|
||||
templateOpts.Values = append(templateOpts.Values, pathutil.ResolvedFilePath(p))
|
||||
}
|
||||
|
||||
for _, p := range appHelm.Parameters {
|
||||
@@ -621,7 +615,11 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
|
||||
}
|
||||
}
|
||||
for _, p := range appHelm.FileParameters {
|
||||
templateOpts.SetFile[p.Name] = p.Path
|
||||
resolvedPath, _, err := pathutil.ResolveFilePath(appPath, repoRoot, env.Envsubst(p.Path), q.GetValuesFileSchemes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
templateOpts.SetFile[p.Name] = resolvedPath
|
||||
}
|
||||
}
|
||||
if templateOpts.Name == "" {
|
||||
@@ -633,9 +631,6 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
|
||||
for i, j := range templateOpts.SetString {
|
||||
templateOpts.SetString[i] = env.Envsubst(j)
|
||||
}
|
||||
for i, j := range templateOpts.SetFile {
|
||||
templateOpts.SetFile[i] = env.Envsubst(j)
|
||||
}
|
||||
|
||||
repos, err := getHelmDependencyRepos(appPath)
|
||||
if err != nil {
|
||||
@@ -708,7 +703,7 @@ func getRepoCredential(repoCredentials []*v1alpha1.RepoCreds, repoURL string) *v
|
||||
}
|
||||
|
||||
// GenerateManifests generates manifests from a path
|
||||
func GenerateManifests(appPath, repoRoot, revision string, q *apiclient.ManifestRequest, isLocal bool) (*apiclient.ManifestResponse, error) {
|
||||
func GenerateManifests(appPath, repoRoot, revision string, q *apiclient.ManifestRequest, isLocal bool, maxCombinedManifestQuantity resource.Quantity) (*apiclient.ManifestResponse, error) {
|
||||
var targetObjs []*unstructured.Unstructured
|
||||
var dest *v1alpha1.ApplicationDestination
|
||||
|
||||
@@ -741,7 +736,8 @@ func GenerateManifests(appPath, repoRoot, revision string, q *apiclient.Manifest
|
||||
if directory = q.ApplicationSource.Directory; directory == nil {
|
||||
directory = &v1alpha1.ApplicationSourceDirectory{}
|
||||
}
|
||||
targetObjs, err = findManifests(appPath, repoRoot, env, *directory)
|
||||
logCtx := log.WithField("application", q.AppName)
|
||||
targetObjs, err = findManifests(logCtx, appPath, repoRoot, env, *directory, maxCombinedManifestQuantity)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -939,44 +935,27 @@ func ksShow(appLabelKey, appPath string, ksonnetOpts *v1alpha1.ApplicationSource
|
||||
var manifestFile = regexp.MustCompile(`^.*\.(yaml|yml|json|jsonnet)$`)
|
||||
|
||||
// findManifests looks at all yaml files in a directory and unmarshals them into a list of unstructured objects
|
||||
func findManifests(appPath string, repoRoot string, env *v1alpha1.Env, directory v1alpha1.ApplicationSourceDirectory) ([]*unstructured.Unstructured, error) {
|
||||
func findManifests(logCtx *log.Entry, appPath string, repoRoot string, env *v1alpha1.Env, directory v1alpha1.ApplicationSourceDirectory, maxCombinedManifestQuantity resource.Quantity) ([]*unstructured.Unstructured, error) {
|
||||
// Validate the directory before loading any manifests to save memory.
|
||||
potentiallyValidManifests, err := getPotentiallyValidManifests(logCtx, appPath, repoRoot, directory.Recurse, directory.Include, directory.Exclude, maxCombinedManifestQuantity)
|
||||
if err != nil {
|
||||
logCtx.Errorf("failed to get potentially valid manifests: %s", err)
|
||||
return nil, fmt.Errorf("failed to get potentially valid manifests: %w", err)
|
||||
}
|
||||
|
||||
var objs []*unstructured.Unstructured
|
||||
err := filepath.Walk(appPath, func(path string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f.IsDir() {
|
||||
if path != appPath && !directory.Recurse {
|
||||
return filepath.SkipDir
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
for _, potentiallyValidManifest := range potentiallyValidManifests {
|
||||
manifestPath := potentiallyValidManifest.path
|
||||
manifestFileInfo := potentiallyValidManifest.fileInfo
|
||||
|
||||
if !manifestFile.MatchString(f.Name()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
relPath, err := filepath.Rel(appPath, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if directory.Exclude != "" && glob.Match(directory.Exclude, relPath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if directory.Include != "" && !glob.Match(directory.Include, relPath) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if strings.HasSuffix(f.Name(), ".jsonnet") {
|
||||
if strings.HasSuffix(manifestFileInfo.Name(), ".jsonnet") {
|
||||
vm, err := makeJsonnetVm(appPath, repoRoot, directory.Jsonnet, env)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
jsonStr, err := vm.EvaluateFile(path)
|
||||
jsonStr, err := vm.EvaluateFile(manifestPath)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to evaluate jsonnet %q: %v", f.Name(), err)
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "Failed to evaluate jsonnet %q: %v", manifestFileInfo.Name(), err)
|
||||
}
|
||||
|
||||
// attempt to unmarshal either array or single object
|
||||
@@ -988,49 +967,207 @@ func findManifests(appPath string, repoRoot string, env *v1alpha1.Env, directory
|
||||
var jsonObj unstructured.Unstructured
|
||||
err = json.Unmarshal([]byte(jsonStr), &jsonObj)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal generated json %q: %v", f.Name(), err)
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "Failed to unmarshal generated json %q: %v", manifestFileInfo.Name(), err)
|
||||
}
|
||||
objs = append(objs, &jsonObj)
|
||||
}
|
||||
} else {
|
||||
out, err := utfutil.ReadFile(path, utfutil.UTF8)
|
||||
err := getObjsFromYAMLOrJson(logCtx, manifestPath, manifestFileInfo.Name(), &objs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if strings.HasSuffix(f.Name(), ".json") {
|
||||
var obj unstructured.Unstructured
|
||||
err = json.Unmarshal(out, &obj)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
}
|
||||
objs = append(objs, &obj)
|
||||
} else {
|
||||
yamlObjs, err := kube.SplitYAML(out)
|
||||
if err != nil {
|
||||
if len(yamlObjs) > 0 {
|
||||
// If we get here, we had a multiple objects in a single YAML file which had some
|
||||
// valid k8s objects, but errors parsing others (within the same file). It's very
|
||||
// likely the user messed up a portion of the YAML, so report on that.
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
}
|
||||
// Otherwise, let's see if it looks like a resource, if yes, we return error
|
||||
if bytes.Contains(out, []byte("apiVersion:")) &&
|
||||
bytes.Contains(out, []byte("kind:")) &&
|
||||
bytes.Contains(out, []byte("metadata:")) {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
}
|
||||
// Otherwise, it might be a unrelated YAML file which we will ignore
|
||||
return nil
|
||||
}
|
||||
objs = append(objs, yamlObjs...)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return objs, nil
|
||||
}
|
||||
|
||||
// getObjsFromYAMLOrJson unmarshals the given yaml or json file and appends it to the given list of objects.
|
||||
func getObjsFromYAMLOrJson(logCtx *log.Entry, manifestPath string, filename string, objs *[]*unstructured.Unstructured) error {
|
||||
reader, err := utfutil.OpenFile(manifestPath, utfutil.UTF8)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to open %q", manifestPath)
|
||||
}
|
||||
defer func() {
|
||||
err := reader.Close()
|
||||
if err != nil {
|
||||
logCtx.Errorf("failed to close %q - potential memory leak", manifestPath)
|
||||
}
|
||||
}()
|
||||
if strings.HasSuffix(filename, ".json") {
|
||||
var obj unstructured.Unstructured
|
||||
decoder := json.NewDecoder(reader)
|
||||
err = decoder.Decode(&obj)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", filename, err)
|
||||
}
|
||||
if decoder.More() {
|
||||
return status.Errorf(codes.FailedPrecondition, "Found multiple objects in %q. Only single objects are allowed in JSON files.", filename)
|
||||
}
|
||||
*objs = append(*objs, &obj)
|
||||
} else {
|
||||
yamlObjs, err := splitYAMLOrJSON(reader)
|
||||
if err != nil {
|
||||
if len(yamlObjs) > 0 {
|
||||
// If we get here, we had a multiple objects in a single YAML file which had some
|
||||
// valid k8s objects, but errors parsing others (within the same file). It's very
|
||||
// likely the user messed up a portion of the YAML, so report on that.
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", filename, err)
|
||||
}
|
||||
// Read the whole file to check whether it looks like a manifest.
|
||||
out, err := utfutil.ReadFile(manifestPath, utfutil.UTF8)
|
||||
// Otherwise, let's see if it looks like a resource, if yes, we return error
|
||||
if bytes.Contains(out, []byte("apiVersion:")) &&
|
||||
bytes.Contains(out, []byte("kind:")) &&
|
||||
bytes.Contains(out, []byte("metadata:")) {
|
||||
return status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", filename, err)
|
||||
}
|
||||
// Otherwise, it might be an unrelated YAML file which we will ignore
|
||||
}
|
||||
*objs = append(*objs, yamlObjs...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// splitYAMLOrJSON reads a YAML or JSON file and gets each document as an unstructured object. If the unmarshaller
|
||||
// encounters an error, objects read up until the error are returned.
|
||||
func splitYAMLOrJSON(reader goio.Reader) ([]*unstructured.Unstructured, error) {
|
||||
d := kubeyaml.NewYAMLOrJSONDecoder(reader, 4096)
|
||||
var objs []*unstructured.Unstructured
|
||||
for {
|
||||
u := &unstructured.Unstructured{}
|
||||
if err := d.Decode(&u); err != nil {
|
||||
if err == goio.EOF {
|
||||
break
|
||||
}
|
||||
return objs, fmt.Errorf("failed to unmarshal manifest: %v", err)
|
||||
}
|
||||
if u == nil {
|
||||
continue
|
||||
}
|
||||
objs = append(objs, u)
|
||||
}
|
||||
return objs, nil
|
||||
}
|
||||
|
||||
// getPotentiallyValidManifestFile checks whether the given path/FileInfo may be a valid manifest file. Returns a non-nil error if
|
||||
// there was an error that should not be handled by ignoring the file. Returns non-nil realFileInfo if the file is a
|
||||
// potential manifest. Returns a non-empty ignoreMessage if there's a message that should be logged about why the file
|
||||
// was skipped. If realFileInfo is nil and the ignoreMessage is empty, there's no need to log the ignoreMessage; the
|
||||
// file was skipped for a mundane reason.
|
||||
//
|
||||
// The file is still only a "potentially" valid manifest file because it could be invalid JSON or YAML, or it might not
|
||||
// be a valid Kubernetes resource. This function tests everything possible without actually reading the file.
|
||||
//
|
||||
// repoPath must be absolute.
|
||||
func getPotentiallyValidManifestFile(path string, f os.FileInfo, appPath, repoRoot, include, exclude string) (realFileInfo os.FileInfo, warning string, err error) {
|
||||
relPath, err := filepath.Rel(appPath, path)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to get relative path of %q: %w", path, err)
|
||||
}
|
||||
|
||||
if !manifestFile.MatchString(f.Name()) {
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
// If the file is a symlink, these will be overridden with the destination file's info.
|
||||
var relRealPath = relPath
|
||||
realFileInfo = f
|
||||
|
||||
if files.IsSymlink(f) {
|
||||
realPath, err := filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, fmt.Sprintf("destination of symlink %q is missing", relPath), nil
|
||||
}
|
||||
return nil, "", fmt.Errorf("failed to evaluate symlink at %q: %w", relPath, err)
|
||||
}
|
||||
if !files.Inbound(realPath, repoRoot) {
|
||||
return nil, "", fmt.Errorf("illegal filepath in symlink at %q", relPath)
|
||||
}
|
||||
realFileInfo, err = os.Stat(realPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// This should have been caught by filepath.EvalSymlinks, but check again since that function's docs
|
||||
// don't promise to return this error.
|
||||
return nil, fmt.Sprintf("destination of symlink %q is missing at %q", relPath, realPath), nil
|
||||
}
|
||||
return nil, "", fmt.Errorf("failed to get file info for symlink at %q to %q: %w", relPath, realPath, err)
|
||||
}
|
||||
relRealPath, err = filepath.Rel(repoRoot, realPath)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to get relative path of %q: %w", realPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
// FileInfo.Size() behavior is platform-specific for non-regular files. Allow only regular files, so we guarantee
|
||||
// accurate file sizes.
|
||||
if !realFileInfo.Mode().IsRegular() {
|
||||
return nil, fmt.Sprintf("ignoring symlink at %q to non-regular file %q", relPath, relRealPath), nil
|
||||
}
|
||||
|
||||
if exclude != "" && glob.Match(exclude, relPath) {
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
if include != "" && !glob.Match(include, relPath) {
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
return realFileInfo, "", nil
|
||||
}
|
||||
|
||||
type potentiallyValidManifest struct {
|
||||
path string
|
||||
fileInfo os.FileInfo
|
||||
}
|
||||
|
||||
// getPotentiallyValidManifests ensures that 1) there are no errors while checking for potential manifest files in the given dir
|
||||
// and 2) the combined file size of the potentially-valid manifest files does not exceed the limit.
|
||||
func getPotentiallyValidManifests(logCtx *log.Entry, appPath string, repoRoot string, recurse bool, include string, exclude string, maxCombinedManifestQuantity resource.Quantity) ([]potentiallyValidManifest, error) {
|
||||
maxCombinedManifestFileSize := maxCombinedManifestQuantity.Value()
|
||||
var currentCombinedManifestFileSize = int64(0)
|
||||
|
||||
var potentiallyValidManifests []potentiallyValidManifest
|
||||
err := filepath.Walk(appPath, func(path string, f os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if f.IsDir() {
|
||||
if path != appPath && !recurse {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
realFileInfo, warning, err := getPotentiallyValidManifestFile(path, f, appPath, repoRoot, include, exclude)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid manifest file %q: %w", path, err)
|
||||
}
|
||||
if realFileInfo == nil {
|
||||
if warning != "" {
|
||||
logCtx.Warnf("skipping manifest file %q: %s", path, warning)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// Don't count jsonnet file size against max. It's jsonnet's responsibility to manage memory usage.
|
||||
if !strings.HasSuffix(f.Name(), ".jsonnet") {
|
||||
// We use the realFileInfo size (which is guaranteed to be a regular file instead of a symlink or other
|
||||
// non-regular file) because .Size() behavior is platform-specific for non-regular files.
|
||||
currentCombinedManifestFileSize += realFileInfo.Size()
|
||||
if maxCombinedManifestFileSize != 0 && currentCombinedManifestFileSize > maxCombinedManifestFileSize {
|
||||
return ErrExceededMaxCombinedManifestFileSize
|
||||
}
|
||||
}
|
||||
potentiallyValidManifests = append(potentiallyValidManifests, potentiallyValidManifest{path: path, fileInfo: f})
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
// Not wrapping, because this error should be wrapped by the caller.
|
||||
return nil, err
|
||||
}
|
||||
return objs, nil
|
||||
|
||||
return potentiallyValidManifests, nil
|
||||
}
|
||||
|
||||
func makeJsonnetVm(appPath string, repoRoot string, sourceJsonnet v1alpha1.ApplicationSourceJsonnet, env *v1alpha1.Env) (*jsonnet.VM, error) {
|
||||
@@ -1060,11 +1197,12 @@ func makeJsonnetVm(appPath string, repoRoot string, sourceJsonnet v1alpha1.Appli
|
||||
// Jsonnet Imports relative to the repository path
|
||||
jpaths := []string{appPath}
|
||||
for _, p := range sourceJsonnet.Libs {
|
||||
jpath := path.Join(repoRoot, p)
|
||||
if !strings.HasPrefix(jpath, repoRoot) {
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "%s: referenced library points outside the repository", p)
|
||||
// the jsonnet library path is relative to the repository root, not application path
|
||||
jpath, _, err := pathutil.ResolveFilePath(repoRoot, repoRoot, p, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jpaths = append(jpaths, jpath)
|
||||
jpaths = append(jpaths, string(jpath))
|
||||
}
|
||||
|
||||
vm.Importer(&jsonnet.FileImporter{
|
||||
@@ -1167,7 +1305,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD
|
||||
return err
|
||||
}
|
||||
case v1alpha1.ApplicationSourceTypeHelm:
|
||||
if err := populateHelmAppDetails(res, ctx.appPath, q); err != nil {
|
||||
if err := populateHelmAppDetails(res, ctx.appPath, repoRoot, q); err != nil {
|
||||
return err
|
||||
}
|
||||
case v1alpha1.ApplicationSourceTypeKustomize:
|
||||
@@ -1229,7 +1367,7 @@ func populateKsonnetAppDetails(res *apiclient.RepoAppDetailsResponse, appPath st
|
||||
return nil
|
||||
}
|
||||
|
||||
func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath string, q *apiclient.RepoServerAppDetailsQuery) error {
|
||||
func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath string, repoRoot string, q *apiclient.RepoServerAppDetailsQuery) error {
|
||||
var selectedValueFiles []string
|
||||
|
||||
if q.Source.Helm != nil {
|
||||
@@ -1258,10 +1396,23 @@ func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath strin
|
||||
return err
|
||||
}
|
||||
|
||||
if err := loadFileIntoIfExists(filepath.Join(appPath, "values.yaml"), &res.Helm.Values); err != nil {
|
||||
return err
|
||||
if resolvedValuesPath, _, err := pathutil.ResolveFilePath(appPath, repoRoot, "values.yaml", []string{}); err == nil {
|
||||
if err := loadFileIntoIfExists(resolvedValuesPath, &res.Helm.Values); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Warnf("Values file %s is not allowed: %v", filepath.Join(appPath, "values.yaml"), err)
|
||||
}
|
||||
params, err := h.GetParameters(selectedValueFiles)
|
||||
var resolvedSelectedValueFiles []pathutil.ResolvedFilePath
|
||||
// drop not allowed values files
|
||||
for _, file := range selectedValueFiles {
|
||||
if resolvedFile, _, err := pathutil.ResolveFilePath(appPath, repoRoot, file, q.GetValuesFileSchemes()); err == nil {
|
||||
resolvedSelectedValueFiles = append(resolvedSelectedValueFiles, resolvedFile)
|
||||
} else {
|
||||
log.Warnf("Values file %s is not allowed: %v", file, err)
|
||||
}
|
||||
}
|
||||
params, err := h.GetParameters(resolvedSelectedValueFiles, appPath, repoRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1280,15 +1431,16 @@ func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath strin
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadFileIntoIfExists(path string, destination *string) error {
|
||||
info, err := os.Stat(path)
|
||||
func loadFileIntoIfExists(path pathutil.ResolvedFilePath, destination *string) error {
|
||||
stringPath := string(path)
|
||||
info, err := os.Stat(stringPath)
|
||||
|
||||
if err == nil && !info.IsDir() {
|
||||
if bytes, err := ioutil.ReadFile(path); err != nil {
|
||||
*destination = string(bytes)
|
||||
} else {
|
||||
bytes, err := ioutil.ReadFile(stringPath);
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*destination = string(bytes)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -28,6 +28,7 @@ message ManifestRequest {
|
||||
bool verifySignature = 16;
|
||||
repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.RepoCreds helmRepoCreds = 17;
|
||||
bool noRevisionCache = 18;
|
||||
github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmOptions helmOptions = 21;
|
||||
}
|
||||
|
||||
// TestRepositoryRequest is a query to test repository is valid or not and has valid access.
|
||||
@@ -82,6 +83,7 @@ message RepoServerAppDetailsQuery {
|
||||
string appName = 5;
|
||||
bool noCache = 6;
|
||||
bool noRevisionCache = 7;
|
||||
github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmOptions helmOptions = 10;
|
||||
}
|
||||
|
||||
// RepoAppDetailsResponse application details
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// +build !race
|
||||
|
||||
package repository
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
)
|
||||
|
||||
func TestHelmDependencyWithConcurrency(t *testing.T) {
|
||||
|
||||
// !race:
|
||||
// Un-synchronized use of a random source, will be fixed when this is merged:
|
||||
// https://github.com/argoproj/argo-cd/issues/4728
|
||||
|
||||
cleanup := func() {
|
||||
_ = os.Remove(filepath.Join("../../util/helm/testdata/helm2-dependency", helmDepUpMarkerFile))
|
||||
_ = os.RemoveAll(filepath.Join("../../util/helm/testdata/helm2-dependency", "charts"))
|
||||
}
|
||||
cleanup()
|
||||
defer cleanup()
|
||||
|
||||
helmRepo := argoappv1.Repository{Name: "bitnami", Type: "helm", Repo: "https://charts.bitnami.com/bitnami"}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(3)
|
||||
for i := 0; i < 3; i++ {
|
||||
go func() {
|
||||
res, err := helmTemplate("../../util/helm/testdata/helm2-dependency", "../..", nil, &apiclient.ManifestRequest{
|
||||
ApplicationSource: &argoappv1.ApplicationSource{},
|
||||
Repos: []*argoappv1.Repository{&helmRepo},
|
||||
}, false)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, res)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
@@ -5,15 +5,20 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
@@ -50,7 +55,7 @@ func newServiceWithMocks(root string, signed bool) (*Service, *gitmocks.Client)
|
||||
return newServiceWithOpt(func(gitClient *gitmocks.Client) {
|
||||
gitClient.On("Init").Return(nil)
|
||||
gitClient.On("Fetch", mock.Anything).Return(nil)
|
||||
gitClient.On("Checkout", mock.Anything).Return(nil)
|
||||
gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil)
|
||||
gitClient.On("LsRemote", mock.Anything).Return(mock.Anything, nil)
|
||||
gitClient.On("CommitSHA").Return(mock.Anything, nil)
|
||||
gitClient.On("Root").Return(root)
|
||||
@@ -79,7 +84,6 @@ func newServiceWithOpt(cf clientFunc) (*Service, *gitmocks.Client) {
|
||||
}}, nil)
|
||||
helmClient.On("ExtractChart", chart, version).Return("./testdata/my-chart", io.NopCloser, nil)
|
||||
helmClient.On("CleanChartCache", chart, version).Return(nil)
|
||||
|
||||
service.newGitClient = func(rawRepoURL string, creds git.Creds, insecure bool, enableLfs bool, prosy string, opts ...git.ClientOpts) (client git.Client, e error) {
|
||||
return gitClient, nil
|
||||
}
|
||||
@@ -110,7 +114,7 @@ func newServiceWithCommitSHA(root, revision string) *Service {
|
||||
service, gitClient := newServiceWithOpt(func(gitClient *gitmocks.Client) {
|
||||
gitClient.On("Init").Return(nil)
|
||||
gitClient.On("Fetch", mock.Anything).Return(nil)
|
||||
gitClient.On("Checkout", mock.Anything).Return(nil)
|
||||
gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil)
|
||||
gitClient.On("LsRemote", revision).Return(revision, revisionErr)
|
||||
gitClient.On("CommitSHA").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil)
|
||||
gitClient.On("Root").Return(root)
|
||||
@@ -138,11 +142,81 @@ func TestGenerateYamlManifestInDir(t *testing.T) {
|
||||
assert.Equal(t, countOfManifests, len(res1.Manifests))
|
||||
|
||||
// this will test concatenated manifests to verify we split YAMLs correctly
|
||||
res2, err := GenerateManifests("./testdata/concatenated", "/", "", &q, false)
|
||||
res2, err := GenerateManifests("./testdata/concatenated", "/", "", &q, false, resource.MustParse("0"))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 3, len(res2.Manifests))
|
||||
}
|
||||
|
||||
func Test_GenerateManifests_NoOutOfBoundsAccess(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
outOfBoundsFilename string
|
||||
outOfBoundsFileContents string
|
||||
mustNotContain string // Optional string that must not appear in error or manifest output. If empty, use outOfBoundsFileContents.
|
||||
}{
|
||||
{
|
||||
name: "out of bounds JSON file should not appear in error output",
|
||||
outOfBoundsFilename: "test.json",
|
||||
outOfBoundsFileContents: `{"some": "json"}`,
|
||||
},
|
||||
{
|
||||
name: "malformed JSON file contents should not appear in error output",
|
||||
outOfBoundsFilename: "test.json",
|
||||
outOfBoundsFileContents: "$",
|
||||
},
|
||||
{
|
||||
name: "out of bounds JSON manifest should not appear in manifest output",
|
||||
outOfBoundsFilename: "test.json",
|
||||
// JSON marshalling is deterministic. So if there's a leak, exactly this should appear in the manifests.
|
||||
outOfBoundsFileContents: `{"apiVersion":"v1","kind":"Secret","metadata":{"name":"test","namespace":"default"},"type":"Opaque"}`,
|
||||
},
|
||||
{
|
||||
name: "out of bounds YAML manifest should not appear in manifest output",
|
||||
outOfBoundsFilename: "test.yaml",
|
||||
outOfBoundsFileContents: "apiVersion: v1\nkind: Secret\nmetadata:\n name: test\n namespace: default\ntype: Opaque",
|
||||
mustNotContain: `{"apiVersion":"v1","kind":"Secret","metadata":{"name":"test","namespace":"default"},"type":"Opaque"}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
testCaseCopy := testCase
|
||||
t.Run(testCaseCopy.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
outOfBoundsDir := t.TempDir()
|
||||
outOfBoundsFile := path.Join(outOfBoundsDir, testCaseCopy.outOfBoundsFilename)
|
||||
err := os.WriteFile(outOfBoundsFile, []byte(testCaseCopy.outOfBoundsFileContents), os.FileMode(0444))
|
||||
require.NoError(t, err)
|
||||
|
||||
repoDir := t.TempDir()
|
||||
err = os.Symlink(outOfBoundsFile, path.Join(repoDir, testCaseCopy.outOfBoundsFilename))
|
||||
require.NoError(t, err)
|
||||
|
||||
var mustNotContain = testCaseCopy.outOfBoundsFileContents
|
||||
if testCaseCopy.mustNotContain != "" {
|
||||
mustNotContain = testCaseCopy.mustNotContain
|
||||
}
|
||||
|
||||
q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &argoappv1.ApplicationSource{}}
|
||||
res, err := GenerateManifests(repoDir, "", "", &q, false, resource.MustParse("0"))
|
||||
require.Error(t, err)
|
||||
assert.NotContains(t, err.Error(), mustNotContain)
|
||||
assert.Contains(t, err.Error(), "illegal filepath")
|
||||
assert.Nil(t, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateManifests_MissingSymlinkDestination(t *testing.T) {
|
||||
repoDir := t.TempDir()
|
||||
err := os.Symlink("/obviously/does/not/exist", path.Join(repoDir, "test.yaml"))
|
||||
require.NoError(t, err)
|
||||
|
||||
q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &argoappv1.ApplicationSource{}}
|
||||
_, err = GenerateManifests(repoDir, "", "", &q, false, resource.MustParse("0"))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGenerateManifests_K8SAPIResetCache(t *testing.T) {
|
||||
service := newService("../..")
|
||||
|
||||
@@ -258,6 +332,25 @@ func TestGenerateJsonnetManifestInDir(t *testing.T) {
|
||||
assert.Equal(t, 2, len(res1.Manifests))
|
||||
}
|
||||
|
||||
func TestGenerateJsonnetLibOutside(t *testing.T) {
|
||||
service := newService(".")
|
||||
|
||||
q := apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: "./testdata/jsonnet",
|
||||
Directory: &argoappv1.ApplicationSourceDirectory{
|
||||
Jsonnet: argoappv1.ApplicationSourceJsonnet{
|
||||
Libs: []string{"../../../testdata/jsonnet/vendor"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
_, err := service.GenerateManifest(context.Background(), &q)
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "value file '../../../testdata/jsonnet/vendor' resolved to outside repository root")
|
||||
}
|
||||
|
||||
func TestGenerateKsonnetManifest(t *testing.T) {
|
||||
service := newService("../..")
|
||||
|
||||
@@ -277,29 +370,6 @@ func TestGenerateKsonnetManifest(t *testing.T) {
|
||||
assert.Equal(t, "https://kubernetes.default.svc", res.Server)
|
||||
}
|
||||
|
||||
func TestGenerateHelmChartWithDependencies(t *testing.T) {
|
||||
service := newService("../..")
|
||||
|
||||
cleanup := func() {
|
||||
_ = os.Remove(filepath.Join("../../util/helm/testdata/helm2-dependency", helmDepUpMarkerFile))
|
||||
_ = os.RemoveAll(filepath.Join("../../util/helm/testdata/helm2-dependency", "charts"))
|
||||
}
|
||||
cleanup()
|
||||
defer cleanup()
|
||||
|
||||
helmRepo := argoappv1.Repository{Name: "bitnami", Type: "helm", Repo: "https://charts.bitnami.com/bitnami"}
|
||||
q := apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: "./util/helm/testdata/helm2-dependency",
|
||||
},
|
||||
Repos: []*argoappv1.Repository{&helmRepo},
|
||||
}
|
||||
res1, err := service.GenerateManifest(context.Background(), &q)
|
||||
assert.Nil(t, err)
|
||||
assert.Len(t, res1.Manifests, 10)
|
||||
}
|
||||
|
||||
func TestManifestGenErrorCacheByNumRequests(t *testing.T) {
|
||||
|
||||
// Returns the state of the manifest generation cache, by querying the cache for the previously set result
|
||||
@@ -726,7 +796,37 @@ func TestHelmManifestFromChartRepoWithValueFileOutsideRepo(t *testing.T) {
|
||||
}
|
||||
request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: source, NoCache: true}
|
||||
_, err := service.GenerateManifest(context.Background(), request)
|
||||
assert.Error(t, err, "should be on or under current directory")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestHelmManifestFromChartRepoWithValueFileLinks(t *testing.T) {
|
||||
t.Run("Valid symlink", func(t *testing.T) {
|
||||
service := newService("../..")
|
||||
source := &argoappv1.ApplicationSource{
|
||||
Chart: "my-chart",
|
||||
TargetRevision: ">= 1.0.0",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"my-chart-link.yaml"},
|
||||
},
|
||||
}
|
||||
request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: source, NoCache: true}
|
||||
_, err := service.GenerateManifest(context.Background(), request)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Symlink pointing to outside", func(t *testing.T) {
|
||||
service := newService("../..")
|
||||
source := &argoappv1.ApplicationSource{
|
||||
Chart: "my-chart",
|
||||
TargetRevision: ">= 1.0.0",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"my-chart-outside-link.yaml"},
|
||||
},
|
||||
}
|
||||
request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: source, NoCache: true}
|
||||
_, err := service.GenerateManifest(context.Background(), request)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "outside repository root")
|
||||
})
|
||||
}
|
||||
|
||||
func TestGenerateHelmWithURL(t *testing.T) {
|
||||
@@ -742,6 +842,7 @@ func TestGenerateHelmWithURL(t *testing.T) {
|
||||
Values: `cluster: {slaveCount: 2}`,
|
||||
},
|
||||
},
|
||||
HelmOptions: &argoappv1.HelmOptions{ValuesFileSchemes: []string{"https"}},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -749,38 +850,108 @@ func TestGenerateHelmWithURL(t *testing.T) {
|
||||
// The requested value file (`../../../../../minio/values.yaml`) is outside the repo directory
|
||||
// (`~/go/src/github.com/argoproj/argo-cd`), so it is blocked
|
||||
func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) {
|
||||
service := newService("../..")
|
||||
_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
AppName: "test",
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: "./util/helm/testdata/redis",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"../../../../../minio/values.yaml"},
|
||||
Values: `cluster: {slaveCount: 2}`,
|
||||
t.Run("Values file with relative path pointing outside repo root", func(t *testing.T) {
|
||||
service := newService("../..")
|
||||
_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
AppName: "test",
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: "./util/helm/testdata/redis",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"../../../../../minio/values.yaml"},
|
||||
Values: `cluster: {slaveCount: 2}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "outside repository root")
|
||||
})
|
||||
assert.Error(t, err, "should be on or under current directory")
|
||||
|
||||
service = newService("./testdata/my-chart")
|
||||
_, err = service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
AppName: "test",
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: ".",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"../my-chart-2/values.yaml"},
|
||||
Values: `cluster: {slaveCount: 2}`,
|
||||
t.Run("Values file with relative path pointing inside repo root", func(t *testing.T) {
|
||||
service := newService("./testdata/my-chart")
|
||||
_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
AppName: "test",
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: ".",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"../my-chart/my-chart-values.yaml"},
|
||||
Values: `cluster: {slaveCount: 2}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Values file with absolute path stays within repo root", func(t *testing.T) {
|
||||
service := newService("./testdata/my-chart")
|
||||
_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
AppName: "test",
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: ".",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"/my-chart-values.yaml"},
|
||||
Values: `cluster: {slaveCount: 2}`,
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("Values file with absolute path using back-references outside repo root", func(t *testing.T) {
|
||||
service := newService("./testdata/my-chart")
|
||||
_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
AppName: "test",
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: ".",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"/../../../my-chart-values.yaml"},
|
||||
Values: `cluster: {slaveCount: 2}`,
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "outside repository root")
|
||||
})
|
||||
|
||||
t.Run("Remote values file from forbidden protocol", func(t *testing.T) {
|
||||
service := newService("./testdata/my-chart")
|
||||
_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
AppName: "test",
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: ".",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"file://../../../../my-chart-values.yaml"},
|
||||
Values: `cluster: {slaveCount: 2}`,
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "is not allowed")
|
||||
})
|
||||
|
||||
t.Run("Remote values file from custom allowed protocol", func(t *testing.T) {
|
||||
service := newService("./testdata/my-chart")
|
||||
_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{},
|
||||
AppName: "test",
|
||||
ApplicationSource: &argoappv1.ApplicationSource{
|
||||
Path: ".",
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"s3://my-bucket/my-chart-values.yaml"},
|
||||
},
|
||||
},
|
||||
HelmOptions: &argoappv1.HelmOptions{ValuesFileSchemes: []string{"s3"}},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "s3://my-bucket/my-chart-values.yaml: no such file or directory")
|
||||
})
|
||||
assert.Error(t, err, "should be on or under current directory")
|
||||
}
|
||||
|
||||
// The requested file parameter (`/tmp/external-secret.txt`) is outside the app path
|
||||
// (`./util/helm/testdata/redis`), and outside the repo directory. It is used as a means
|
||||
// of providing direct content to a helm chart via a specific key.
|
||||
// File parameter should not allow traversal outside of the repository root
|
||||
func TestGenerateHelmWithAbsoluteFileParameter(t *testing.T) {
|
||||
service := newService("../..")
|
||||
|
||||
@@ -802,16 +973,14 @@ func TestGenerateHelmWithAbsoluteFileParameter(t *testing.T) {
|
||||
Helm: &argoappv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"values-production.yaml"},
|
||||
Values: `cluster: {slaveCount: 2}`,
|
||||
FileParameters: []argoappv1.HelmFileParameter{
|
||||
argoappv1.HelmFileParameter{
|
||||
Name: "passwordContent",
|
||||
Path: externalSecretPath,
|
||||
},
|
||||
},
|
||||
FileParameters: []argoappv1.HelmFileParameter{{
|
||||
Name: "passwordContent",
|
||||
Path: externalSecretPath,
|
||||
}},
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
// The requested file parameter (`../external/external-secret.txt`) is outside the app path
|
||||
@@ -931,7 +1100,7 @@ func TestGenerateFromUTF16(t *testing.T) {
|
||||
Repo: &argoappv1.Repository{},
|
||||
ApplicationSource: &argoappv1.ApplicationSource{},
|
||||
}
|
||||
res1, err := GenerateManifests("./testdata/utf-16", "/", "", &q, false)
|
||||
res1, err := GenerateManifests("./testdata/utf-16", "/", "", &q, false, resource.MustParse("0"))
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(res1.Manifests))
|
||||
}
|
||||
@@ -947,12 +1116,15 @@ func TestListApps(t *testing.T) {
|
||||
"app-parameters/multi": "Kustomize",
|
||||
"app-parameters/single-app-only": "Kustomize",
|
||||
"app-parameters/single-global": "Kustomize",
|
||||
"in-bounds-values-file-link": "Helm",
|
||||
"invalid-helm": "Helm",
|
||||
"invalid-kustomize": "Kustomize",
|
||||
"kustomization_yaml": "Kustomize",
|
||||
"kustomization_yml": "Kustomize",
|
||||
"my-chart": "Helm",
|
||||
"my-chart-2": "Helm",
|
||||
"out-of-bounds-values-file-link": "Helm",
|
||||
"values-files": "Helm",
|
||||
}
|
||||
assert.Equal(t, expectedApps, res.Apps)
|
||||
}
|
||||
@@ -1291,6 +1463,7 @@ func runWithTempTestdata(t *testing.T, path string, runner func(t *testing.T, pa
|
||||
tempDir := mkTempParameters("./testdata/app-parameters")
|
||||
defer os.RemoveAll(tempDir)
|
||||
runner(t, filepath.Join(tempDir, "app-parameters", path))
|
||||
os.RemoveAll(tempDir)
|
||||
}
|
||||
|
||||
func TestGenerateManifestsWithAppParameterFile(t *testing.T) {
|
||||
@@ -1492,11 +1665,11 @@ func TestFindResources(t *testing.T) {
|
||||
for i := range testCases {
|
||||
tc := testCases[i]
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
objs, err := findManifests("testdata/app-include-exclude", ".", nil, argoappv1.ApplicationSourceDirectory{
|
||||
objs, err := findManifests(&log.Entry{}, "testdata/app-include-exclude", ".", nil, argoappv1.ApplicationSourceDirectory{
|
||||
Recurse: true,
|
||||
Include: tc.include,
|
||||
Exclude: tc.exclude,
|
||||
})
|
||||
}, resource.MustParse("0"))
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
@@ -1510,10 +1683,10 @@ func TestFindResources(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindManifests_Exclude(t *testing.T) {
|
||||
objs, err := findManifests("testdata/app-include-exclude", ".", nil, argoappv1.ApplicationSourceDirectory{
|
||||
objs, err := findManifests(&log.Entry{}, "testdata/app-include-exclude", ".", nil, argoappv1.ApplicationSourceDirectory{
|
||||
Recurse: true,
|
||||
Exclude: "subdir/deploymentSub.yaml",
|
||||
})
|
||||
}, resource.MustParse("0"))
|
||||
|
||||
if !assert.NoError(t, err) || !assert.Len(t, objs, 1) {
|
||||
return
|
||||
@@ -1523,10 +1696,10 @@ func TestFindManifests_Exclude(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFindManifests_Exclude_NothingMatches(t *testing.T) {
|
||||
objs, err := findManifests("testdata/app-include-exclude", ".", nil, argoappv1.ApplicationSourceDirectory{
|
||||
objs, err := findManifests(&log.Entry{}, "testdata/app-include-exclude", ".", nil, argoappv1.ApplicationSourceDirectory{
|
||||
Recurse: true,
|
||||
Exclude: "nothing.yaml",
|
||||
})
|
||||
}, resource.MustParse("0"))
|
||||
|
||||
if !assert.NoError(t, err) || !assert.Len(t, objs, 2) {
|
||||
return
|
||||
@@ -1536,6 +1709,469 @@ func TestFindManifests_Exclude_NothingMatches(t *testing.T) {
|
||||
[]string{"nginx-deployment", "nginx-deployment-sub"}, []string{objs[0].GetName(), objs[1].GetName()})
|
||||
}
|
||||
|
||||
func tempDir(t *testing.T) string {
|
||||
dir, err := ioutil.TempDir(".", "")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
err = os.RemoveAll(dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
absDir, err := filepath.Abs(dir)
|
||||
require.NoError(t, err)
|
||||
return absDir
|
||||
}
|
||||
|
||||
func walkFor(t *testing.T, root string, testPath string, run func(info fs.FileInfo)) {
|
||||
var hitExpectedPath = false
|
||||
err := filepath.Walk(root, func(path string, info fs.FileInfo, err error) error {
|
||||
if path == testPath {
|
||||
require.NoError(t, err)
|
||||
hitExpectedPath = true
|
||||
run(info)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, hitExpectedPath, "did not hit expected path when walking directory")
|
||||
}
|
||||
|
||||
func Test_getPotentiallyValidManifestFile(t *testing.T) {
|
||||
// These tests use filepath.Walk instead of os.Stat to get file info, because FileInfo from os.Stat does not return
|
||||
// true for IsSymlink like os.Walk does.
|
||||
|
||||
// These tests do not use t.TempDir() because those directories can contain symlinks which cause test to fail
|
||||
// InBound checks.
|
||||
|
||||
t.Run("non-JSON/YAML is skipped with an empty ignore message", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
filePath := filepath.Join(appDir, "not-json-or-yaml")
|
||||
file, err := os.OpenFile(filePath, os.O_RDONLY|os.O_CREATE, 0644)
|
||||
require.NoError(t, err)
|
||||
err = file.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, filePath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(filePath, info, appDir, appDir, "", "")
|
||||
assert.Nil(t, realFileInfo)
|
||||
assert.Empty(t, ignoreMessage)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("circular link should throw an error", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
|
||||
aPath := filepath.Join(appDir, "a.json")
|
||||
bPath := filepath.Join(appDir, "b.json")
|
||||
err := os.Symlink(bPath, aPath)
|
||||
require.NoError(t, err)
|
||||
err = os.Symlink(aPath, bPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, aPath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(aPath, info, appDir, appDir, "", "")
|
||||
assert.Nil(t, realFileInfo)
|
||||
assert.Empty(t, ignoreMessage)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "too many links")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("symlink with missing destination should throw an error", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
|
||||
aPath := filepath.Join(appDir, "a.json")
|
||||
bPath := filepath.Join(appDir, "b.json")
|
||||
err := os.Symlink(bPath, aPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, aPath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(aPath, info, appDir, appDir, "", "")
|
||||
assert.Nil(t, realFileInfo)
|
||||
assert.NotEmpty(t, ignoreMessage)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("out-of-bounds symlink should throw an error", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
|
||||
linkPath := filepath.Join(appDir, "a.json")
|
||||
err := os.Symlink("..", linkPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, linkPath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(linkPath, info, appDir, appDir, "", "")
|
||||
assert.Nil(t, realFileInfo)
|
||||
assert.Empty(t, ignoreMessage)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "illegal filepath in symlink")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("symlink to a non-regular file should be skipped with warning", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
|
||||
dirPath := filepath.Join(appDir, "test.dir")
|
||||
err := os.MkdirAll(dirPath, 0644)
|
||||
require.NoError(t, err)
|
||||
linkPath := filepath.Join(appDir, "test.json")
|
||||
err = os.Symlink(dirPath, linkPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, linkPath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(linkPath, info, appDir, appDir, "", "")
|
||||
assert.Nil(t, realFileInfo)
|
||||
assert.Contains(t, ignoreMessage, "non-regular file")
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("non-included file should be skipped with no message", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
|
||||
filePath := filepath.Join(appDir, "not-included.yaml")
|
||||
file, err := os.OpenFile(filePath, os.O_RDONLY|os.O_CREATE, 0644)
|
||||
require.NoError(t, err)
|
||||
err = file.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, filePath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(filePath, info, appDir, appDir, "*.json", "")
|
||||
assert.Nil(t, realFileInfo)
|
||||
assert.Empty(t, ignoreMessage)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("excluded file should be skipped with no message", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
|
||||
filePath := filepath.Join(appDir, "excluded.json")
|
||||
file, err := os.OpenFile(filePath, os.O_RDONLY|os.O_CREATE, 0644)
|
||||
require.NoError(t, err)
|
||||
err = file.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, filePath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(filePath, info, appDir, appDir, "", "excluded.*")
|
||||
assert.Nil(t, realFileInfo)
|
||||
assert.Empty(t, ignoreMessage)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("symlink to a regular file is potentially valid", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
|
||||
filePath := filepath.Join(appDir, "regular-file")
|
||||
file, err := os.OpenFile(filePath, os.O_RDONLY|os.O_CREATE, 0644)
|
||||
require.NoError(t, err)
|
||||
err = file.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
linkPath := filepath.Join(appDir, "link.json")
|
||||
err = os.Symlink(filePath, linkPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, linkPath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(linkPath, info, appDir, appDir, "", "")
|
||||
assert.NotNil(t, realFileInfo)
|
||||
assert.Empty(t, ignoreMessage)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("a regular file is potentially valid", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
|
||||
filePath := filepath.Join(appDir, "regular-file.json")
|
||||
file, err := os.OpenFile(filePath, os.O_RDONLY|os.O_CREATE, 0644)
|
||||
require.NoError(t, err)
|
||||
err = file.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, filePath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(filePath, info, appDir, appDir, "", "")
|
||||
assert.NotNil(t, realFileInfo)
|
||||
assert.Empty(t, ignoreMessage)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("realFileInfo is for the destination rather than the symlink", func(t *testing.T) {
|
||||
appDir := tempDir(t)
|
||||
|
||||
filePath := filepath.Join(appDir, "regular-file")
|
||||
file, err := os.OpenFile(filePath, os.O_RDONLY|os.O_CREATE, 0644)
|
||||
require.NoError(t, err)
|
||||
err = file.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
linkPath := filepath.Join(appDir, "link.json")
|
||||
err = os.Symlink(filePath, linkPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
walkFor(t, appDir, linkPath, func(info fs.FileInfo) {
|
||||
realFileInfo, ignoreMessage, err := getPotentiallyValidManifestFile(linkPath, info, appDir, appDir, "", "")
|
||||
assert.NotNil(t, realFileInfo)
|
||||
assert.Equal(t, filepath.Base(filePath), realFileInfo.Name())
|
||||
assert.Empty(t, ignoreMessage)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_getPotentiallyValidManifests(t *testing.T) {
|
||||
// Tests which return no manifests and an error check to make sure the directory exists before running. A missing
|
||||
// directory would produce those same results.
|
||||
|
||||
logCtx := log.WithField("test", "test")
|
||||
|
||||
t.Run("unreadable file throws error", func(t *testing.T) {
|
||||
appDir := t.TempDir()
|
||||
unreadablePath := filepath.Join(appDir, "unreadable.json")
|
||||
err := os.WriteFile(unreadablePath, []byte{}, 0666)
|
||||
require.NoError(t, err)
|
||||
err = os.Chmod(appDir, 0000)
|
||||
require.NoError(t, err)
|
||||
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, appDir, appDir, false, "", "", resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
|
||||
// allow cleanup
|
||||
err = os.Chmod(appDir, 0777)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("no recursion when recursion is disabled", func(t *testing.T) {
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, "./testdata/recurse", "./testdata/recurse", false, "", "", resource.MustParse("0"))
|
||||
assert.Len(t, manifests, 1)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("recursion when recursion is enabled", func(t *testing.T) {
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, "./testdata/recurse", "./testdata/recurse", true, "", "", resource.MustParse("0"))
|
||||
assert.Len(t, manifests, 2)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("non-JSON/YAML is skipped", func(t *testing.T) {
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, "./testdata/non-manifest-file", "./testdata/non-manifest-file", false, "", "", resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("circular link should throw an error", func(t *testing.T) {
|
||||
require.DirExists(t, "./testdata/circular-link")
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, "./testdata/circular-link", "./testdata/circular-link", false, "", "", resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("out-of-bounds symlink should throw an error", func(t *testing.T) {
|
||||
require.DirExists(t, "./testdata/out-of-bounds-link")
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, "./testdata/out-of-bounds-link", "./testdata/out-of-bounds-link", false, "", "", resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("symlink to a regular file works", func(t *testing.T) {
|
||||
repoRoot, err := filepath.Abs("./testdata/in-bounds-link")
|
||||
require.NoError(t, err)
|
||||
appPath, err := filepath.Abs("./testdata/in-bounds-link/app")
|
||||
require.NoError(t, err)
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, appPath, repoRoot, false, "", "", resource.MustParse("0"))
|
||||
assert.Len(t, manifests, 1)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("symlink to nowhere should be ignored", func(t *testing.T) {
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, "./testdata/link-to-nowhere", "./testdata/link-to-nowhere", false, "", "", resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("link to over-sized manifest fails", func(t *testing.T) {
|
||||
repoRoot, err := filepath.Abs("./testdata/in-bounds-link")
|
||||
require.NoError(t, err)
|
||||
appPath, err := filepath.Abs("./testdata/in-bounds-link/app")
|
||||
require.NoError(t, err)
|
||||
// The file is 35 bytes.
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, appPath, repoRoot, false, "", "", resource.MustParse("34"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.ErrorIs(t, err, ErrExceededMaxCombinedManifestFileSize)
|
||||
})
|
||||
|
||||
t.Run("group of files should be limited at precisely the sum of their size", func(t *testing.T) {
|
||||
// There is a total of 10 files, ech file being 10 bytes.
|
||||
manifests, err := getPotentiallyValidManifests(logCtx, "./testdata/several-files", "./testdata/several-files", false, "", "", resource.MustParse("365"))
|
||||
assert.Len(t, manifests, 10)
|
||||
assert.NoError(t, err)
|
||||
|
||||
manifests, err = getPotentiallyValidManifests(logCtx, "./testdata/several-files", "./testdata/several-files", false, "", "", resource.MustParse("100"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.ErrorIs(t, err, ErrExceededMaxCombinedManifestFileSize)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_findManifests(t *testing.T) {
|
||||
logCtx := log.WithField("test", "test")
|
||||
noRecurse := argoappv1.ApplicationSourceDirectory{Recurse: false}
|
||||
|
||||
t.Run("unreadable file throws error", func(t *testing.T) {
|
||||
appDir := t.TempDir()
|
||||
unreadablePath := filepath.Join(appDir, "unreadable.json")
|
||||
err := os.WriteFile(unreadablePath, []byte{}, 0666)
|
||||
require.NoError(t, err)
|
||||
err = os.Chmod(appDir, 0000)
|
||||
require.NoError(t, err)
|
||||
|
||||
manifests, err := findManifests(logCtx, appDir, appDir, nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
|
||||
// allow cleanup
|
||||
err = os.Chmod(appDir, 0777)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("no recursion when recursion is disabled", func(t *testing.T) {
|
||||
manifests, err := findManifests(logCtx, "./testdata/recurse", "./testdata/recurse", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Len(t, manifests, 2)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("recursion when recursion is enabled", func(t *testing.T) {
|
||||
recurse := argoappv1.ApplicationSourceDirectory{Recurse: true}
|
||||
manifests, err := findManifests(logCtx, "./testdata/recurse", "./testdata/recurse", nil, recurse, resource.MustParse("0"))
|
||||
assert.Len(t, manifests, 4)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("non-JSON/YAML is skipped", func(t *testing.T) {
|
||||
manifests, err := findManifests(logCtx, "./testdata/non-manifest-file", "./testdata/non-manifest-file", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("circular link should throw an error", func(t *testing.T) {
|
||||
require.DirExists(t, "./testdata/circular-link")
|
||||
manifests, err := findManifests(logCtx, "./testdata/circular-link", "./testdata/circular-link", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("out-of-bounds symlink should throw an error", func(t *testing.T) {
|
||||
require.DirExists(t, "./testdata/out-of-bounds-link")
|
||||
manifests, err := findManifests(logCtx, "./testdata/out-of-bounds-link", "./testdata/out-of-bounds-link", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("symlink to a regular file works", func(t *testing.T) {
|
||||
repoRoot, err := filepath.Abs("./testdata/in-bounds-link")
|
||||
require.NoError(t, err)
|
||||
appPath, err := filepath.Abs("./testdata/in-bounds-link/app")
|
||||
require.NoError(t, err)
|
||||
manifests, err := findManifests(logCtx, appPath, repoRoot, nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Len(t, manifests, 1)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("symlink to nowhere should be ignored", func(t *testing.T) {
|
||||
manifests, err := findManifests(logCtx, "./testdata/link-to-nowhere", "./testdata/link-to-nowhere", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("link to over-sized manifest fails", func(t *testing.T) {
|
||||
repoRoot, err := filepath.Abs("./testdata/in-bounds-link")
|
||||
require.NoError(t, err)
|
||||
appPath, err := filepath.Abs("./testdata/in-bounds-link/app")
|
||||
require.NoError(t, err)
|
||||
// The file is 35 bytes.
|
||||
manifests, err := findManifests(logCtx, appPath, repoRoot, nil, noRecurse, resource.MustParse("34"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.ErrorIs(t, err, ErrExceededMaxCombinedManifestFileSize)
|
||||
})
|
||||
|
||||
t.Run("group of files should be limited at precisely the sum of their size", func(t *testing.T) {
|
||||
// There is a total of 10 files, each file being 10 bytes.
|
||||
manifests, err := findManifests(logCtx, "./testdata/several-files", "./testdata/several-files", nil, noRecurse, resource.MustParse("365"))
|
||||
assert.Len(t, manifests, 10)
|
||||
assert.NoError(t, err)
|
||||
|
||||
manifests, err = findManifests(logCtx, "./testdata/several-files", "./testdata/several-files", nil, noRecurse, resource.MustParse("364"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.ErrorIs(t, err, ErrExceededMaxCombinedManifestFileSize)
|
||||
})
|
||||
|
||||
t.Run("jsonnet isn't counted against size limit", func(t *testing.T) {
|
||||
// Each file is 36 bytes. Only the 36-byte json file should be counted against the limit.
|
||||
manifests, err := findManifests(logCtx, "./testdata/jsonnet-and-json", "./testdata/jsonnet-and-json", nil, noRecurse, resource.MustParse("36"))
|
||||
assert.Len(t, manifests, 2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
manifests, err = findManifests(logCtx, "./testdata/jsonnet-and-json", "./testdata/jsonnet-and-json", nil, noRecurse, resource.MustParse("35"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.ErrorIs(t, err, ErrExceededMaxCombinedManifestFileSize)
|
||||
})
|
||||
|
||||
t.Run("partially valid YAML file throws an error", func(t *testing.T) {
|
||||
require.DirExists(t, "./testdata/partially-valid-yaml")
|
||||
manifests, err := findManifests(logCtx, "./testdata/partially-valid-yaml", "./testdata/partially-valid-yaml", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("invalid manifest throws an error", func(t *testing.T) {
|
||||
require.DirExists(t, "./testdata/invalid-manifests")
|
||||
manifests, err := findManifests(logCtx, "./testdata/invalid-manifests", "./testdata/invalid-manifests", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("irrelevant YAML gets skipped, relevant YAML gets parsed", func(t *testing.T) {
|
||||
manifests, err := findManifests(logCtx, "./testdata/irrelevant-yaml", "./testdata/irrelevant-yaml", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Len(t, manifests, 1)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("multiple JSON objects in one file throws an error", func(t *testing.T) {
|
||||
require.DirExists(t, "./testdata/json-list")
|
||||
manifests, err := findManifests(logCtx, "./testdata/json-list", "./testdata/json-list", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("invalid JSON throws an error", func(t *testing.T) {
|
||||
require.DirExists(t, "./testdata/invalid-json")
|
||||
manifests, err := findManifests(logCtx, "./testdata/invalid-json", "./testdata/invalid-json", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Empty(t, manifests)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("valid JSON returns manifest and no error", func(t *testing.T) {
|
||||
manifests, err := findManifests(logCtx, "./testdata/valid-json", "./testdata/valid-json", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Len(t, manifests, 1)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("YAML with an empty document doesn't throw an error", func(t *testing.T) {
|
||||
manifests, err := findManifests(logCtx, "./testdata/yaml-with-empty-document", "./testdata/yaml-with-empty-document", nil, noRecurse, resource.MustParse("0"))
|
||||
assert.Len(t, manifests, 1)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTestRepoOCI(t *testing.T) {
|
||||
service := newService(".")
|
||||
_, err := service.TestRepository(context.Background(), &apiclient.TestRepositoryRequest{
|
||||
@@ -1559,3 +2195,52 @@ func Test_getHelmDependencyRepos(t *testing.T) {
|
||||
assert.Equal(t, repos[0].Repo, repo1)
|
||||
assert.Equal(t, repos[1].Repo, repo2)
|
||||
}
|
||||
|
||||
func Test_findHelmValueFilesInPath(t *testing.T) {
|
||||
t.Run("does not exist", func(t *testing.T) {
|
||||
files, err := findHelmValueFilesInPath("/obviously/does/not/exist")
|
||||
assert.Error(t, err)
|
||||
assert.Empty(t, files)
|
||||
})
|
||||
t.Run("values files", func(t *testing.T) {
|
||||
files, err := findHelmValueFilesInPath("./testdata/values-files")
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, files, 4)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_populateHelmAppDetails(t *testing.T) {
|
||||
res := apiclient.RepoAppDetailsResponse{}
|
||||
q := apiclient.RepoServerAppDetailsQuery{
|
||||
Repo: &argoappv1.Repository{},
|
||||
Source: &argoappv1.ApplicationSource{
|
||||
Helm: &argoappv1.ApplicationSourceHelm{ValueFiles: []string{"exclude.yaml", "has-the-word-values.yaml"}},
|
||||
},
|
||||
}
|
||||
appPath, err := filepath.Abs("./testdata/values-files/")
|
||||
require.NoError(t, err)
|
||||
err = populateHelmAppDetails(&res, appPath, appPath, &q)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, res.Helm.Parameters, 3)
|
||||
assert.Len(t, res.Helm.ValueFiles, 4)
|
||||
}
|
||||
|
||||
func Test_populateHelmAppDetails_values_symlinks(t *testing.T) {
|
||||
t.Run("inbound", func(t *testing.T) {
|
||||
res := apiclient.RepoAppDetailsResponse{}
|
||||
q := apiclient.RepoServerAppDetailsQuery{Repo: &argoappv1.Repository{}, Source: &argoappv1.ApplicationSource{}}
|
||||
err := populateHelmAppDetails(&res, "./testdata/in-bounds-values-file-link/", "./testdata/in-bounds-values-file-link/", &q)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, res.Helm.Values)
|
||||
assert.NotEmpty(t, res.Helm.Parameters)
|
||||
})
|
||||
|
||||
t.Run("out of bounds", func(t *testing.T) {
|
||||
res := apiclient.RepoAppDetailsResponse{}
|
||||
q := apiclient.RepoServerAppDetailsQuery{Repo: &argoappv1.Repository{}, Source: &argoappv1.ApplicationSource{}}
|
||||
err := populateHelmAppDetails(&res, "./testdata/out-of-bounds-values-file-link/", "./testdata/out-of-bounds-values-file-link/", &q)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, res.Helm.Values)
|
||||
assert.Empty(t, res.Helm.Parameters)
|
||||
})
|
||||
}
|
||||
|
||||
1
reposerver/repository/testdata/circular-link/a.json
vendored
Symbolic link
1
reposerver/repository/testdata/circular-link/a.json
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
b.json
|
||||
1
reposerver/repository/testdata/circular-link/b.json
vendored
Symbolic link
1
reposerver/repository/testdata/circular-link/b.json
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
a.json
|
||||
1
reposerver/repository/testdata/in-bounds-link/app/cm.link.yaml
vendored
Symbolic link
1
reposerver/repository/testdata/in-bounds-link/app/cm.link.yaml
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../cm.yaml
|
||||
2
reposerver/repository/testdata/in-bounds-link/cm.yaml
vendored
Normal file
2
reposerver/repository/testdata/in-bounds-link/cm.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
2
reposerver/repository/testdata/in-bounds-values-file-link/Chart.yaml
vendored
Normal file
2
reposerver/repository/testdata/in-bounds-values-file-link/Chart.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
name: my-chart
|
||||
version: 1.1.0
|
||||
1
reposerver/repository/testdata/in-bounds-values-file-link/values-2.yaml
vendored
Normal file
1
reposerver/repository/testdata/in-bounds-values-file-link/values-2.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
some: yaml
|
||||
1
reposerver/repository/testdata/in-bounds-values-file-link/values.yaml
vendored
Symbolic link
1
reposerver/repository/testdata/in-bounds-values-file-link/values.yaml
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
values-2.yaml
|
||||
1
reposerver/repository/testdata/invalid-json/invalid.json
vendored
Normal file
1
reposerver/repository/testdata/invalid-json/invalid.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[
|
||||
1
reposerver/repository/testdata/irrelevant-yaml/irrelevant.yaml
vendored
Normal file
1
reposerver/repository/testdata/irrelevant-yaml/irrelevant.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
some: [irrelevant, yaml]
|
||||
2
reposerver/repository/testdata/irrelevant-yaml/relevant.yaml
vendored
Normal file
2
reposerver/repository/testdata/irrelevant-yaml/relevant.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
2
reposerver/repository/testdata/json-list/list.json
vendored
Normal file
2
reposerver/repository/testdata/json-list/list.json
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
{"apiVersion": "v1", "kind": "ConfigMap"}
|
||||
{"apiVersion": "v1", "kind": "ConfigMap"}
|
||||
1
reposerver/repository/testdata/jsonnet-and-json/test.json
vendored
Normal file
1
reposerver/repository/testdata/jsonnet-and-json/test.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"apiVersion": "v1", "kind": "Pod"}
|
||||
1
reposerver/repository/testdata/jsonnet-and-json/test.jsonnet
vendored
Normal file
1
reposerver/repository/testdata/jsonnet-and-json/test.jsonnet
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"apiVersion": "v1", "kind": "Pod"}
|
||||
1
reposerver/repository/testdata/link-to-nowhere/nowhere.json
vendored
Symbolic link
1
reposerver/repository/testdata/link-to-nowhere/nowhere.json
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
nowhere
|
||||
1
reposerver/repository/testdata/my-chart/my-chart-link.yaml
vendored
Symbolic link
1
reposerver/repository/testdata/my-chart/my-chart-link.yaml
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
my-chart-values.yaml
|
||||
1
reposerver/repository/testdata/my-chart/my-chart-outside-link.yaml
vendored
Symbolic link
1
reposerver/repository/testdata/my-chart/my-chart-outside-link.yaml
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../my-chart-2/my-chart-2-values.yaml
|
||||
0
reposerver/repository/testdata/non-manifest-file/not-json-or-yaml
vendored
Normal file
0
reposerver/repository/testdata/non-manifest-file/not-json-or-yaml
vendored
Normal file
1
reposerver/repository/testdata/out-of-bounds-link/out-of-bounds.json
vendored
Symbolic link
1
reposerver/repository/testdata/out-of-bounds-link/out-of-bounds.json
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../out-of-bounds.json
|
||||
2
reposerver/repository/testdata/out-of-bounds-values-file-link/Chart.yaml
vendored
Normal file
2
reposerver/repository/testdata/out-of-bounds-values-file-link/Chart.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
name: my-chart
|
||||
version: 1.1.0
|
||||
1
reposerver/repository/testdata/out-of-bounds-values-file-link/values.yaml
vendored
Symbolic link
1
reposerver/repository/testdata/out-of-bounds-values-file-link/values.yaml
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../out-of-bounds.yaml
|
||||
0
reposerver/repository/testdata/out-of-bounds.json
vendored
Normal file
0
reposerver/repository/testdata/out-of-bounds.json
vendored
Normal file
1
reposerver/repository/testdata/out-of-bounds.yaml
vendored
Normal file
1
reposerver/repository/testdata/out-of-bounds.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
some: yaml
|
||||
4
reposerver/repository/testdata/partially-valid-yaml/partially-valid.yaml
vendored
Normal file
4
reposerver/repository/testdata/partially-valid-yaml/partially-valid.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
---
|
||||
invalid:
|
||||
1
reposerver/repository/testdata/several-files/0.json
vendored
Normal file
1
reposerver/repository/testdata/several-files/0.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"apiVersion": "v1", "kind": "ConfigMap"}
|
||||
2
reposerver/repository/testdata/several-files/0.yaml
vendored
Normal file
2
reposerver/repository/testdata/several-files/0.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
1
reposerver/repository/testdata/several-files/1.json
vendored
Normal file
1
reposerver/repository/testdata/several-files/1.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"apiVersion": "v1", "kind": "ConfigMap"}
|
||||
2
reposerver/repository/testdata/several-files/1.yaml
vendored
Normal file
2
reposerver/repository/testdata/several-files/1.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
1
reposerver/repository/testdata/several-files/2.json
vendored
Normal file
1
reposerver/repository/testdata/several-files/2.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"apiVersion": "v1", "kind": "ConfigMap"}
|
||||
2
reposerver/repository/testdata/several-files/2.yaml
vendored
Normal file
2
reposerver/repository/testdata/several-files/2.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
1
reposerver/repository/testdata/several-files/3.json
vendored
Normal file
1
reposerver/repository/testdata/several-files/3.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"apiVersion": "v1", "kind": "ConfigMap"}
|
||||
2
reposerver/repository/testdata/several-files/3.yaml
vendored
Normal file
2
reposerver/repository/testdata/several-files/3.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
1
reposerver/repository/testdata/several-files/4.json
vendored
Normal file
1
reposerver/repository/testdata/several-files/4.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"apiVersion": "v1", "kind": "ConfigMap"}
|
||||
2
reposerver/repository/testdata/several-files/4.yaml
vendored
Normal file
2
reposerver/repository/testdata/several-files/4.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
1
reposerver/repository/testdata/several-files/README.md
vendored
Normal file
1
reposerver/repository/testdata/several-files/README.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
This file shouldn't be counted in the manifest file size limit, because it isn't JSON or YAML.
|
||||
1
reposerver/repository/testdata/valid-json/valid.json
vendored
Normal file
1
reposerver/repository/testdata/valid-json/valid.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"apiVersion": "v1", "kind": "ConfigMap"}
|
||||
2
reposerver/repository/testdata/values-files/Chart.yaml
vendored
Normal file
2
reposerver/repository/testdata/values-files/Chart.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
name: my-chart
|
||||
version: 1.1.0
|
||||
0
reposerver/repository/testdata/values-files/caps-extn-values.YAML
vendored
Normal file
0
reposerver/repository/testdata/values-files/caps-extn-values.YAML
vendored
Normal file
1
reposerver/repository/testdata/values-files/exclude.yaml
vendored
Normal file
1
reposerver/repository/testdata/values-files/exclude.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
exclude: yaml
|
||||
4
reposerver/repository/testdata/values-files/has-the-word-values.yaml
vendored
Normal file
4
reposerver/repository/testdata/values-files/has-the-word-values.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
has:
|
||||
the:
|
||||
word:
|
||||
values: yaml
|
||||
1
reposerver/repository/testdata/values-files/values.yaml
vendored
Normal file
1
reposerver/repository/testdata/values-files/values.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
values: yaml
|
||||
0
reposerver/repository/testdata/values-files/values.yml
vendored
Normal file
0
reposerver/repository/testdata/values-files/values.yml
vendored
Normal file
4
reposerver/repository/testdata/yaml-with-empty-document/has-empty.yaml
vendored
Normal file
4
reposerver/repository/testdata/yaml-with-empty-document/has-empty.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
---
|
||||
---
|
||||
@@ -229,6 +229,7 @@ func (s *Server) queryRepoServer(ctx context.Context, a *v1alpha1.Application, a
|
||||
repo *appv1.Repository,
|
||||
helmRepos []*appv1.Repository,
|
||||
helmCreds []*v1alpha1.RepoCreds,
|
||||
helmOptions *v1alpha1.HelmOptions,
|
||||
kustomizeOptions *v1alpha1.KustomizeOptions,
|
||||
) error) error {
|
||||
|
||||
@@ -270,11 +271,15 @@ func (s *Server) queryRepoServer(ctx context.Context, a *v1alpha1.Application, a
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
helmOptions, err := s.settingsMgr.GetHelmSettings()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
permittedHelmCredentials, err := argo.GetPermittedReposCredentials(proj, helmRepositoryCredentials)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return action(client, repo, permittedHelmRepos, permittedHelmCredentials, kustomizeOptions)
|
||||
return action(client, repo, permittedHelmRepos, permittedHelmCredentials, helmOptions, kustomizeOptions)
|
||||
}
|
||||
|
||||
// GetManifests returns application manifests
|
||||
@@ -289,7 +294,7 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan
|
||||
|
||||
var manifestInfo *apiclient.ManifestResponse
|
||||
err = s.queryRepoServer(ctx, a, func(
|
||||
client apiclient.RepoServerServiceClient, repo *appv1.Repository, helmRepos []*appv1.Repository, helmCreds []*appv1.RepoCreds, kustomizeOptions *appv1.KustomizeOptions) error {
|
||||
client apiclient.RepoServerServiceClient, repo *appv1.Repository, helmRepos []*appv1.Repository, helmCreds []*appv1.RepoCreds, helmOptions *appv1.HelmOptions, kustomizeOptions *appv1.KustomizeOptions) error {
|
||||
revision := a.Spec.Source.TargetRevision
|
||||
if q.Revision != "" {
|
||||
revision = q.Revision
|
||||
@@ -331,6 +336,7 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan
|
||||
KubeVersion: serverVersion,
|
||||
ApiVersions: argo.APIGroupsToVersions(apiGroups),
|
||||
HelmRepoCreds: helmCreds,
|
||||
HelmOptions: helmOptions,
|
||||
})
|
||||
return err
|
||||
})
|
||||
@@ -405,6 +411,7 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app
|
||||
repo *appv1.Repository,
|
||||
helmRepos []*appv1.Repository,
|
||||
_ []*appv1.RepoCreds,
|
||||
helmOptions *appv1.HelmOptions,
|
||||
kustomizeOptions *appv1.KustomizeOptions,
|
||||
) error {
|
||||
_, err := client.GetAppDetails(ctx, &apiclient.RepoServerAppDetailsQuery{
|
||||
@@ -414,6 +421,7 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app
|
||||
KustomizeOptions: kustomizeOptions,
|
||||
Repos: helmRepos,
|
||||
NoCache: true,
|
||||
HelmOptions: helmOptions,
|
||||
})
|
||||
return err
|
||||
}); err != nil {
|
||||
@@ -470,6 +478,21 @@ func (s *Server) ListResourceEvents(ctx context.Context, q *application.Applicat
|
||||
"involvedObject.namespace": a.Namespace,
|
||||
}).String()
|
||||
} else {
|
||||
tree, err := s.getAppResources(ctx, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
found := false
|
||||
for _, n := range append(tree.Nodes, tree.OrphanedNodes...) {
|
||||
if n.ResourceRef.UID == q.ResourceUID && n.ResourceRef.Name == q.ResourceName && n.ResourceRef.Namespace == q.ResourceNamespace {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "%s not found as part of application %s", q.ResourceName, *q.Name)
|
||||
}
|
||||
|
||||
namespace = q.ResourceNamespace
|
||||
var config *rest.Config
|
||||
config, err = s.getApplicationClusterConfig(ctx, a)
|
||||
@@ -486,7 +509,6 @@ func (s *Server) ListResourceEvents(ctx context.Context, q *application.Applicat
|
||||
"involvedObject.namespace": namespace,
|
||||
}).String()
|
||||
}
|
||||
|
||||
log.Infof("Querying for resource events with field selector: %s", fieldSelector)
|
||||
opts := metav1.ListOptions{FieldSelector: fieldSelector}
|
||||
return kubeClientset.CoreV1().Events(namespace).List(ctx, opts)
|
||||
@@ -848,7 +870,7 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica
|
||||
|
||||
var conditions []appv1.ApplicationCondition
|
||||
if validate {
|
||||
conditions, err = argo.ValidateRepo(ctx, app, s.repoClientset, s.db, kustomizeOptions, plugins, s.kubectl, proj)
|
||||
conditions, err = argo.ValidateRepo(ctx, app, s.repoClientset, s.db, kustomizeOptions, plugins, s.kubectl, proj, s.settingsMgr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -912,7 +934,7 @@ func (s *Server) getAppResources(ctx context.Context, a *appv1.Application) (*ap
|
||||
return &tree, err
|
||||
}
|
||||
|
||||
func (s *Server) getAppResource(ctx context.Context, action string, q *application.ApplicationResourceRequest) (*appv1.ResourceNode, *rest.Config, *appv1.Application, error) {
|
||||
func (s *Server) getAppLiveResource(ctx context.Context, action string, q *application.ApplicationResourceRequest) (*appv1.ResourceNode, *rest.Config, *appv1.Application, error) {
|
||||
a, err := s.appLister.Get(*q.Name)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
@@ -927,7 +949,7 @@ func (s *Server) getAppResource(ctx context.Context, action string, q *applicati
|
||||
}
|
||||
|
||||
found := tree.FindNode(q.Group, q.Kind, q.Namespace, q.ResourceName)
|
||||
if found == nil {
|
||||
if found == nil || found.ResourceRef.UID == "" {
|
||||
return nil, nil, nil, status.Errorf(codes.InvalidArgument, "%s %s %s not found as part of application %s", q.Kind, q.Group, q.ResourceName, *q.Name)
|
||||
}
|
||||
config, err := s.getApplicationClusterConfig(ctx, a)
|
||||
@@ -938,7 +960,7 @@ func (s *Server) getAppResource(ctx context.Context, action string, q *applicati
|
||||
}
|
||||
|
||||
func (s *Server) GetResource(ctx context.Context, q *application.ApplicationResourceRequest) (*application.ApplicationResourceResponse, error) {
|
||||
res, config, _, err := s.getAppResource(ctx, rbacpolicy.ActionGet, q)
|
||||
res, config, _, err := s.getAppLiveResource(ctx, rbacpolicy.ActionGet, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -983,7 +1005,7 @@ func (s *Server) PatchResource(ctx context.Context, q *application.ApplicationRe
|
||||
Version: q.Version,
|
||||
Group: q.Group,
|
||||
}
|
||||
res, config, a, err := s.getAppResource(ctx, rbacpolicy.ActionUpdate, resourceRequest)
|
||||
res, config, a, err := s.getAppLiveResource(ctx, rbacpolicy.ActionUpdate, resourceRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1023,7 +1045,7 @@ func (s *Server) DeleteResource(ctx context.Context, q *application.ApplicationR
|
||||
Version: q.Version,
|
||||
Group: q.Group,
|
||||
}
|
||||
res, config, a, err := s.getAppResource(ctx, rbacpolicy.ActionDelete, resourceRequest)
|
||||
res, config, a, err := s.getAppLiveResource(ctx, rbacpolicy.ActionDelete, resourceRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1293,7 +1315,7 @@ func getSelectedPods(treeNodes []appv1.ResourceNode, q *application.ApplicationP
|
||||
var pods []appv1.ResourceNode
|
||||
isTheOneMap := make(map[string]bool)
|
||||
for _, treeNode := range treeNodes {
|
||||
if treeNode.Kind == kube.PodKind && treeNode.Group == "" {
|
||||
if treeNode.Kind == kube.PodKind && treeNode.Group == "" && treeNode.UID != "" {
|
||||
if isTheSelectedOne(&treeNode, q, treeNodes, isTheOneMap) {
|
||||
pods = append(pods, treeNode)
|
||||
}
|
||||
@@ -1603,7 +1625,7 @@ func (s *Server) logResourceEvent(res *appv1.ResourceNode, ctx context.Context,
|
||||
}
|
||||
|
||||
func (s *Server) ListResourceActions(ctx context.Context, q *application.ApplicationResourceRequest) (*application.ResourceActionsListResponse, error) {
|
||||
res, config, _, err := s.getAppResource(ctx, rbacpolicy.ActionGet, q)
|
||||
res, config, _, err := s.getAppLiveResource(ctx, rbacpolicy.ActionGet, q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1654,7 +1676,7 @@ func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceA
|
||||
Group: q.Group,
|
||||
}
|
||||
actionRequest := fmt.Sprintf("%s/%s/%s/%s", rbacpolicy.ActionAction, q.Group, q.Kind, q.Action)
|
||||
res, config, a, err := s.getAppResource(ctx, actionRequest, resourceRequest)
|
||||
res, config, a, err := s.getAppLiveResource(ctx, actionRequest, resourceRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -10,11 +10,14 @@ import (
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
repositorypkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
appsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
servercache "github.com/argoproj/argo-cd/v2/server/cache"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
@@ -31,6 +34,8 @@ type Server struct {
|
||||
repoClientset apiclient.Clientset
|
||||
enf *rbac.Enforcer
|
||||
cache *servercache.Cache
|
||||
appLister applisters.ApplicationNamespaceLister
|
||||
projLister applisters.AppProjectNamespaceLister
|
||||
settings *settings.SettingsManager
|
||||
}
|
||||
|
||||
@@ -40,6 +45,8 @@ func NewServer(
|
||||
db db.ArgoDB,
|
||||
enf *rbac.Enforcer,
|
||||
cache *servercache.Cache,
|
||||
appLister applisters.ApplicationNamespaceLister,
|
||||
projLister applisters.AppProjectNamespaceLister,
|
||||
settings *settings.SettingsManager,
|
||||
) *Server {
|
||||
return &Server{
|
||||
@@ -47,10 +54,31 @@ func NewServer(
|
||||
repoClientset: repoClientset,
|
||||
enf: enf,
|
||||
cache: cache,
|
||||
appLister: appLister,
|
||||
projLister: projLister,
|
||||
settings: settings,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
errPermissionDenied = status.Error(codes.PermissionDenied, "permission denied")
|
||||
)
|
||||
|
||||
func (s *Server) getRepo(ctx context.Context, url string) (*appsv1.Repository, error) {
|
||||
repo, err := s.db.GetRepository(ctx, url)
|
||||
if err != nil {
|
||||
return nil, errPermissionDenied
|
||||
}
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func createRBACObject(project string, repo string) string {
|
||||
if project != "" {
|
||||
return project + "/" + repo
|
||||
}
|
||||
return repo
|
||||
}
|
||||
|
||||
// Get the connection state for a given repository URL by connecting to the
|
||||
// repo and evaluate the results. Unless forceRefresh is set to true, the
|
||||
// result may be retrieved out of the cache.
|
||||
@@ -183,7 +211,8 @@ func (s *Server) ListRefs(ctx context.Context, q *repositorypkg.RepoQuery) (*api
|
||||
})
|
||||
}
|
||||
|
||||
// ListApps returns list of apps in the repo
|
||||
// ListApps performs discovery of a git repository for potential sources of applications. Used
|
||||
// as a convenience to the UI for auto-complete.
|
||||
func (s *Server) ListApps(ctx context.Context, q *repositorypkg.RepoAppsQuery) (*repositorypkg.RepoAppsResponse, error) {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, q.Repo); err != nil {
|
||||
return nil, err
|
||||
@@ -193,6 +222,24 @@ func (s *Server) ListApps(ctx context.Context, q *repositorypkg.RepoAppsQuery) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
claims := ctx.Value("claims")
|
||||
if err := s.enf.EnforceErr(claims, rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, createRBACObject("", repo.Repo)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// This endpoint causes us to clone git repos & invoke config management tooling for the purposes
|
||||
// of app discovery. Only allow this to happen if user has privileges to create or update the
|
||||
// application which it wants to retrieve these details for.
|
||||
appRBACresource := fmt.Sprintf("%s/%s", q.AppProject, q.AppName)
|
||||
if !s.enf.Enforce(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionCreate, appRBACresource) &&
|
||||
!s.enf.Enforce(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, appRBACresource) {
|
||||
return nil, errPermissionDenied
|
||||
}
|
||||
// Also ensure the repo is actually allowed in the project in question
|
||||
if err := s.isRepoPermittedInProject(q.Repo, q.AppProject); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Test the repo
|
||||
conn, repoClient, err := s.repoClientset.NewRepoServerClient()
|
||||
if err != nil {
|
||||
@@ -214,6 +261,9 @@ func (s *Server) ListApps(ctx context.Context, q *repositorypkg.RepoAppsQuery) (
|
||||
return &repositorypkg.RepoAppsResponse{Items: items}, nil
|
||||
}
|
||||
|
||||
// GetAppDetails shows parameter values to various config tools (e.g. helm/kustomize values)
|
||||
// This is used by UI for parameter form fields during app create & edit pages.
|
||||
// It is also used when showing history of parameters used in previous syncs in the app history.
|
||||
func (s *Server) GetAppDetails(ctx context.Context, q *repositorypkg.RepoAppDetailsQuery) (*apiclient.RepoAppDetailsResponse, error) {
|
||||
if q.Source == nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "missing payload in request")
|
||||
@@ -221,10 +271,44 @@ func (s *Server) GetAppDetails(ctx context.Context, q *repositorypkg.RepoAppDeta
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, q.Source.RepoURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repo, err := s.db.GetRepository(ctx, q.Source.RepoURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
claims := ctx.Value("claims")
|
||||
if err := s.enf.EnforceErr(claims, rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, createRBACObject("", repo.Repo)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
app, err := s.appLister.Get(q.AppName)
|
||||
appRBACObj := createRBACObject(q.AppProject, q.AppName)
|
||||
// ensure caller has read privileges to app
|
||||
if err := s.enf.EnforceErr(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, appRBACObj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if apierr.IsNotFound(err) {
|
||||
// app doesn't exist since it still is being formulated. verify they can create the app
|
||||
// before we reveal repo details
|
||||
if err := s.enf.EnforceErr(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionCreate, appRBACObj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// if we get here we are returning repo details of an existing app
|
||||
if q.AppProject != app.Spec.Project {
|
||||
return nil, errPermissionDenied
|
||||
}
|
||||
// verify caller is not making a request with arbitrary source values which were not in our history
|
||||
if !isSourceInHistory(app, *q.Source) {
|
||||
return nil, errPermissionDenied
|
||||
}
|
||||
}
|
||||
// Ensure the repo is actually allowed in the project in question
|
||||
if err := s.isRepoPermittedInProject(q.Source.RepoURL, q.AppProject); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn, repoClient, err := s.repoClientset.NewRepoServerClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -242,11 +326,16 @@ func (s *Server) GetAppDetails(ctx context.Context, q *repositorypkg.RepoAppDeta
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
helmOptions, err := s.settings.GetHelmSettings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repoClient.GetAppDetails(ctx, &apiclient.RepoServerAppDetailsQuery{
|
||||
Repo: repo,
|
||||
Source: q.Source,
|
||||
Repos: helmRepos,
|
||||
KustomizeOptions: kustomizeOptions,
|
||||
HelmOptions: helmOptions,
|
||||
AppName: q.AppName,
|
||||
})
|
||||
}
|
||||
@@ -427,3 +516,33 @@ func (s *Server) testRepo(ctx context.Context, repo *appsv1.Repository) error {
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) isRepoPermittedInProject(repo string, projName string) error {
|
||||
proj, err := s.projLister.Get(projName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !proj.IsSourcePermitted(appsv1.ApplicationSource{RepoURL: repo}) {
|
||||
return status.Errorf(codes.PermissionDenied, "repository '%s' not permitted in project '%s'", repo, projName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// isSourceInHistory checks if the supplied application source is either our current application
|
||||
// source, or was something which we synced to previously.
|
||||
func isSourceInHistory(app *v1alpha1.Application, source v1alpha1.ApplicationSource) bool {
|
||||
if source.Equals(app.Spec.Source) {
|
||||
return true
|
||||
}
|
||||
// Iterate history. When comparing items in our history, use the actual synced revision to
|
||||
// compare with the supplied source.targetRevision in the request. This is because
|
||||
// history[].source.targetRevision is ambiguous (e.g. HEAD), whereas
|
||||
// history[].revision will contain the explicit SHA
|
||||
for _, h := range app.Status.History {
|
||||
h.Source.TargetRevision = h.Revision
|
||||
if source.Equals(h.Source) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import "github.com/argoproj/argo-cd/v2/reposerver/repository/repository.proto";
|
||||
message RepoAppsQuery {
|
||||
string repo = 1;
|
||||
string revision = 2;
|
||||
string appName = 3;
|
||||
string appProject = 4;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +31,7 @@ message AppInfo {
|
||||
message RepoAppDetailsQuery {
|
||||
github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSource source = 1;
|
||||
string appName = 2;
|
||||
string appProject = 3;
|
||||
}
|
||||
|
||||
// RepoAppsResponse contains applications of specified repository
|
||||
|
||||
562
server/repository/repository_test.go
Normal file
562
server/repository/repository_test.go
Normal file
@@ -0,0 +1,562 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apiclient/repository"
|
||||
appsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
fakeapps "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake"
|
||||
appinformer "github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions"
|
||||
applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks"
|
||||
"github.com/argoproj/argo-cd/v2/server/cache"
|
||||
"github.com/argoproj/argo-cd/v2/util/assets"
|
||||
cacheutil "github.com/argoproj/argo-cd/v2/util/cache"
|
||||
appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks"
|
||||
"github.com/argoproj/argo-cd/v2/util/rbac"
|
||||
"github.com/argoproj/argo-cd/v2/util/settings"
|
||||
)
|
||||
|
||||
const testNamespace = "default"
|
||||
|
||||
var (
|
||||
argocdCM = corev1.ConfigMap{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Namespace: testNamespace,
|
||||
Name: "argocd-cm",
|
||||
Labels: map[string]string{
|
||||
"app.kubernetes.io/part-of": "argocd",
|
||||
},
|
||||
},
|
||||
}
|
||||
argocdSecret = corev1.Secret{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "argocd-secret",
|
||||
Namespace: testNamespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"admin.password": []byte("test"),
|
||||
"server.secretkey": []byte("test"),
|
||||
},
|
||||
}
|
||||
defaultProj = &appsv1.AppProject{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "AppProject",
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
Namespace: testNamespace,
|
||||
},
|
||||
Spec: appsv1.AppProjectSpec{
|
||||
SourceRepos: []string{"*"},
|
||||
Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}},
|
||||
},
|
||||
}
|
||||
|
||||
defaultProjNoSources = &appsv1.AppProject{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "AppProject",
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
Namespace: testNamespace,
|
||||
},
|
||||
Spec: appsv1.AppProjectSpec{
|
||||
SourceRepos: []string{},
|
||||
Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}},
|
||||
},
|
||||
}
|
||||
|
||||
guestbookApp = &appsv1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Application",
|
||||
APIVersion: "argoproj.io/v1alpha1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "guestbook",
|
||||
Namespace: testNamespace,
|
||||
},
|
||||
Spec: appsv1.ApplicationSpec{
|
||||
Project: "default",
|
||||
Source: appsv1.ApplicationSource{
|
||||
RepoURL: "https://test",
|
||||
TargetRevision: "HEAD",
|
||||
Helm: &appsv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"values.yaml"},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: appsv1.ApplicationStatus{
|
||||
History: appsv1.RevisionHistories{
|
||||
{
|
||||
Revision: "abcdef123567",
|
||||
Source: appsv1.ApplicationSource{
|
||||
RepoURL: "https://test",
|
||||
TargetRevision: "HEAD",
|
||||
Helm: &appsv1.ApplicationSourceHelm{
|
||||
ValueFiles: []string{"values-old.yaml"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func newAppAndProjLister(objects ...runtime.Object) (applisters.ApplicationNamespaceLister, applisters.AppProjectNamespaceLister) {
|
||||
fakeAppsClientset := fakeapps.NewSimpleClientset(objects...)
|
||||
factory := appinformer.NewSharedInformerFactoryWithOptions(fakeAppsClientset, 0, appinformer.WithNamespace(""), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {}))
|
||||
projInformer := factory.Argoproj().V1alpha1().AppProjects()
|
||||
appsInformer := factory.Argoproj().V1alpha1().Applications()
|
||||
for _, obj := range objects {
|
||||
switch obj.(type) {
|
||||
case *appsv1.AppProject:
|
||||
_ = projInformer.Informer().GetStore().Add(obj)
|
||||
case *appsv1.Application:
|
||||
_ = appsInformer.Informer().GetStore().Add(obj)
|
||||
}
|
||||
}
|
||||
appLister := appsInformer.Lister().Applications(testNamespace)
|
||||
projLister := projInformer.Lister().AppProjects(testNamespace)
|
||||
return appLister, projLister
|
||||
}
|
||||
|
||||
func Test_createRBACObject(t *testing.T) {
|
||||
object := createRBACObject("test-prj", "test-repo")
|
||||
assert.Equal(t, "test-prj/test-repo", object)
|
||||
objectWithoutPrj := createRBACObject("", "test-repo")
|
||||
assert.Equal(t, "test-repo", objectWithoutPrj)
|
||||
}
|
||||
|
||||
func TestRepositoryServer(t *testing.T) {
|
||||
kubeclientset := fake.NewSimpleClientset(&argocdCM, &argocdSecret)
|
||||
settingsMgr := settings.NewSettingsManager(context.Background(), kubeclientset, testNamespace)
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj)
|
||||
argoDB := db.NewDB("default", settingsMgr, kubeclientset)
|
||||
|
||||
t.Run("Test_getRepo", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
|
||||
s := NewServer(&repoServerClientset, argoDB, enforcer, nil, appLister, projLister, settingsMgr)
|
||||
url := "https://test"
|
||||
repo, _ := s.getRepo(context.TODO(), url)
|
||||
assert.Equal(t, repo.Repo, url)
|
||||
})
|
||||
|
||||
t.Run("Test_validateAccess", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil)
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
|
||||
s := NewServer(&repoServerClientset, argoDB, enforcer, nil, appLister, projLister, settingsMgr)
|
||||
url := "https://test"
|
||||
_, err := s.ValidateAccess(context.TODO(), &repository.RepoAccessQuery{
|
||||
Repo: url,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("Test_Get", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil)
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
db.On("RepositoryExists", context.TODO(), url).Return(true, nil)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
repo, err := s.Get(context.TODO(), &repository.RepoQuery{
|
||||
Repo: url,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, repo.Repo, url)
|
||||
})
|
||||
|
||||
t.Run("Test_CreateRepositoryWithoutUpsert", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil)
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), "test").Return(nil, errors.New("not found"))
|
||||
db.On("CreateRepository", context.TODO(), mock.Anything).Return(&apiclient.TestRepositoryResponse{}).Return(&appsv1.Repository{
|
||||
Repo: "repo",
|
||||
}, nil)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
repo, err := s.CreateRepository(context.TODO(), &repository.RepoCreateRequest{
|
||||
Repo: &appsv1.Repository{
|
||||
Repo: "test",
|
||||
Username: "test",
|
||||
},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, repo.Repo, "repo")
|
||||
})
|
||||
|
||||
t.Run("Test_CreateRepositoryWithUpsert", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil)
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), "test").Return(&appsv1.Repository{
|
||||
Repo: "test",
|
||||
Username: "test",
|
||||
}, nil)
|
||||
db.On("CreateRepository", context.TODO(), mock.Anything).Return(nil, status.Errorf(codes.AlreadyExists, "repository already exists"))
|
||||
db.On("UpdateRepository", context.TODO(), mock.Anything).Return(nil, nil)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
repo, err := s.CreateRepository(context.TODO(), &repository.RepoCreateRequest{
|
||||
Repo: &appsv1.Repository{
|
||||
Repo: "test",
|
||||
Username: "test",
|
||||
},
|
||||
Upsert: true,
|
||||
})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, repo.Repo, "test")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestRepositoryServerListApps(t *testing.T) {
|
||||
kubeclientset := fake.NewSimpleClientset(&argocdCM, &argocdSecret)
|
||||
settingsMgr := settings.NewSettingsManager(context.Background(), kubeclientset, testNamespace)
|
||||
|
||||
t.Run("Test_WithoutAppCreateUpdatePrivileges", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
enforcer.SetDefaultRole("role:readonly")
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.ListApps(context.TODO(), &repository.RepoAppsQuery{
|
||||
Repo: "https://test",
|
||||
Revision: "HEAD",
|
||||
AppName: "foo",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.Nil(t, resp)
|
||||
assert.Equal(t, err, errPermissionDenied)
|
||||
})
|
||||
|
||||
t.Run("Test_WithAppCreateUpdatePrivileges", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
enforcer.SetDefaultRole("role:admin")
|
||||
appLister, projLister := newAppAndProjLister(defaultProj)
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
repoServerClient.On("ListApps", context.TODO(), mock.Anything).Return(&apiclient.AppList{
|
||||
Apps: map[string]string{
|
||||
"path/to/dir": "Kustomize",
|
||||
},
|
||||
}, nil)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.ListApps(context.TODO(), &repository.RepoAppsQuery{
|
||||
Repo: "https://test",
|
||||
Revision: "HEAD",
|
||||
AppName: "foo",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, resp.Items, 1)
|
||||
assert.Equal(t, "path/to/dir", resp.Items[0].Path)
|
||||
assert.Equal(t, "Kustomize", resp.Items[0].Type)
|
||||
})
|
||||
|
||||
t.Run("Test_WithAppCreateUpdatePrivilegesRepoNotAllowed", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
enforcer.SetDefaultRole("role:admin")
|
||||
appLister, projLister := newAppAndProjLister(defaultProjNoSources)
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
repoServerClient.On("ListApps", context.TODO(), mock.Anything).Return(&apiclient.AppList{
|
||||
Apps: map[string]string{
|
||||
"path/to/dir": "Kustomize",
|
||||
},
|
||||
}, nil)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.ListApps(context.TODO(), &repository.RepoAppsQuery{
|
||||
Repo: "https://test",
|
||||
Revision: "HEAD",
|
||||
AppName: "foo",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.Nil(t, resp)
|
||||
assert.Error(t, err, "repository 'https://test' not permitted in project 'default'")
|
||||
})
|
||||
}
|
||||
|
||||
func TestRepositoryServerGetAppDetails(t *testing.T) {
|
||||
kubeclientset := fake.NewSimpleClientset(&argocdCM, &argocdSecret)
|
||||
settingsMgr := settings.NewSettingsManager(context.Background(), kubeclientset, testNamespace)
|
||||
|
||||
t.Run("Test_WithoutRepoReadPrivileges", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
enforcer.SetDefaultRole("")
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{
|
||||
Source: &appsv1.ApplicationSource{
|
||||
RepoURL: url,
|
||||
},
|
||||
AppName: "newapp",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.Nil(t, resp)
|
||||
assert.Error(t, err, "rpc error: code = PermissionDenied desc = permission denied: repositories, get, https://test")
|
||||
})
|
||||
t.Run("Test_WithoutAppReadPrivileges", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
_ = enforcer.SetUserPolicy("p, role:readrepos, repositories, get, *, allow")
|
||||
enforcer.SetDefaultRole("role:readrepos")
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{
|
||||
Source: &appsv1.ApplicationSource{
|
||||
RepoURL: url,
|
||||
},
|
||||
AppName: "newapp",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.Nil(t, resp)
|
||||
assert.Error(t, err, "rpc error: code = PermissionDenied desc = permission denied: applications, get, default/newapp")
|
||||
})
|
||||
t.Run("Test_WithoutCreatePrivileges", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
enforcer.SetDefaultRole("role:readonly")
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{
|
||||
Source: &appsv1.ApplicationSource{
|
||||
RepoURL: url,
|
||||
},
|
||||
AppName: "newapp",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.Nil(t, resp)
|
||||
assert.Error(t, err, "rpc error: code = PermissionDenied desc = permission denied: applications, create, default/newapp")
|
||||
})
|
||||
t.Run("Test_WithCreatePrivileges", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("ListHelmRepositories", context.TODO(), mock.Anything).Return(nil, nil)
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
expectedResp := apiclient.RepoAppDetailsResponse{Type: "Directory"}
|
||||
repoServerClient.On("GetAppDetails", context.TODO(), mock.Anything).Return(&expectedResp, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{
|
||||
Source: &appsv1.ApplicationSource{
|
||||
RepoURL: url,
|
||||
},
|
||||
AppName: "newapp",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedResp, *resp)
|
||||
})
|
||||
t.Run("Test_RepoNotPermitted", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
expectedResp := apiclient.RepoAppDetailsResponse{Type: "Directory"}
|
||||
repoServerClient.On("GetAppDetails", context.TODO(), mock.Anything).Return(&expectedResp, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProjNoSources)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{
|
||||
Source: &appsv1.ApplicationSource{
|
||||
RepoURL: url,
|
||||
},
|
||||
AppName: "newapp",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.Error(t, err, "repository 'https://test' not permitted in project 'default'")
|
||||
assert.Nil(t, resp)
|
||||
})
|
||||
t.Run("Test_ExistingApp", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("ListHelmRepositories", context.TODO(), mock.Anything).Return(nil, nil)
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
expectedResp := apiclient.RepoAppDetailsResponse{Type: "Directory"}
|
||||
repoServerClient.On("GetAppDetails", context.TODO(), mock.Anything).Return(&expectedResp, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj, guestbookApp)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{
|
||||
Source: &guestbookApp.Spec.Source,
|
||||
AppName: "guestbook",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedResp, *resp)
|
||||
})
|
||||
t.Run("Test_ExistingAppMismatchedProjectName", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj, guestbookApp)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{
|
||||
Source: &guestbookApp.Spec.Source,
|
||||
AppName: "guestbook",
|
||||
AppProject: "mismatch",
|
||||
})
|
||||
assert.Equal(t, errPermissionDenied, err)
|
||||
assert.Nil(t, resp)
|
||||
})
|
||||
t.Run("Test_ExistingAppSourceNotInHistory", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj, guestbookApp)
|
||||
differentSource := guestbookApp.Spec.Source.DeepCopy()
|
||||
differentSource.Helm.ValueFiles = []string{"/etc/passwd"}
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{
|
||||
Source: differentSource,
|
||||
AppName: "guestbook",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.Equal(t, errPermissionDenied, err)
|
||||
assert.Nil(t, resp)
|
||||
})
|
||||
t.Run("Test_ExistingAppSourceInHistory", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil)
|
||||
db.On("ListHelmRepositories", context.TODO(), mock.Anything).Return(nil, nil)
|
||||
expectedResp := apiclient.RepoAppDetailsResponse{Type: "Directory"}
|
||||
repoServerClient.On("GetAppDetails", context.TODO(), mock.Anything).Return(&expectedResp, nil)
|
||||
appLister, projLister := newAppAndProjLister(defaultProj, guestbookApp)
|
||||
previousSource := guestbookApp.Status.History[0].Source.DeepCopy()
|
||||
previousSource.TargetRevision = guestbookApp.Status.History[0].Revision
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{
|
||||
Source: previousSource,
|
||||
AppName: "guestbook",
|
||||
AppProject: "default",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedResp, *resp)
|
||||
})
|
||||
}
|
||||
|
||||
type fixtures struct {
|
||||
*cache.Cache
|
||||
}
|
||||
|
||||
func newFixtures() *fixtures {
|
||||
return &fixtures{cache.NewCache(
|
||||
appstatecache.NewCache(
|
||||
cacheutil.NewCache(cacheutil.NewInMemoryCache(1*time.Hour)),
|
||||
1*time.Minute,
|
||||
),
|
||||
1*time.Minute,
|
||||
1*time.Minute,
|
||||
1*time.Minute,
|
||||
)}
|
||||
}
|
||||
|
||||
func newEnforcer(kubeclientset *fake.Clientset) *rbac.Enforcer {
|
||||
enforcer := rbac.NewEnforcer(kubeclientset, testNamespace, common.ArgoCDRBACConfigMapName, nil)
|
||||
_ = enforcer.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
|
||||
enforcer.SetDefaultRole("role:admin")
|
||||
enforcer.SetClaimsEnforcerFunc(func(claims jwt.Claims, rvals ...interface{}) bool {
|
||||
return true
|
||||
})
|
||||
return enforcer
|
||||
}
|
||||
@@ -154,6 +154,7 @@ type ArgoCDServer struct {
|
||||
settingsMgr *settings_util.SettingsManager
|
||||
enf *rbac.Enforcer
|
||||
projInformer cache.SharedIndexInformer
|
||||
projLister applisters.AppProjectNamespaceLister
|
||||
policyEnforcer *rbacpolicy.RBACPolicyEnforcer
|
||||
appInformer cache.SharedIndexInformer
|
||||
appLister applisters.ApplicationNamespaceLister
|
||||
@@ -248,6 +249,7 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer {
|
||||
settingsMgr: settingsMgr,
|
||||
enf: enf,
|
||||
projInformer: projInformer,
|
||||
projLister: projLister,
|
||||
appInformer: appInformer,
|
||||
appLister: appLister,
|
||||
policyEnforcer: policyEnf,
|
||||
@@ -560,7 +562,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
|
||||
db := db.NewDB(a.Namespace, a.settingsMgr, a.KubeClientset)
|
||||
kubectl := kubeutil.NewKubectl()
|
||||
clusterService := cluster.NewServer(db, a.enf, a.Cache, kubectl)
|
||||
repoService := repository.NewServer(a.RepoClientset, db, a.enf, a.Cache, a.settingsMgr)
|
||||
repoService := repository.NewServer(a.RepoClientset, db, a.enf, a.Cache, a.appLister, a.projLister, a.settingsMgr)
|
||||
repoCredsService := repocreds.NewServer(a.RepoClientset, db, a.enf, a.settingsMgr)
|
||||
var loginRateLimiter func() (io.Closer, error)
|
||||
if maxConcurrentLoginRequestsCount > 0 {
|
||||
@@ -945,6 +947,9 @@ func (a *ArgoCDServer) Authenticate(ctx context.Context) (context.Context, error
|
||||
}
|
||||
if !argoCDSettings.AnonymousUserEnabled {
|
||||
return ctx, claimsErr
|
||||
} else {
|
||||
// nolint:staticcheck
|
||||
ctx = context.WithValue(ctx, "claims", "")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user