diff --git a/Dockerfile b/Dockerfile index d34a4cae52fc0..4a8590a767fee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -107,7 +107,6 @@ RUN groupadd -g 999 argocd && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -COPY hack/ssh_known_hosts /etc/ssh/ssh_known_hosts COPY hack/git-ask-pass.sh /usr/local/bin/git-ask-pass.sh COPY --from=builder /usr/local/bin/ks /usr/local/bin/ks COPY --from=builder /usr/local/bin/helm /usr/local/bin/helm @@ -116,6 +115,13 @@ COPY --from=builder /usr/local/bin/kustomize1 /usr/local/bin/kustomize1 COPY --from=builder /usr/local/bin/kustomize /usr/local/bin/kustomize COPY --from=builder /usr/local/bin/aws-iam-authenticator /usr/local/bin/aws-iam-authenticator +# support for mounting configuration from a configmap +RUN mkdir -p /app/config/ssh && \ + touch /app/config/ssh/ssh_known_hosts && \ + ln -s /app/config/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts + +RUN mkdir -p /app/config/tls + # workaround ksonnet issue https://github.com/ksonnet/ksonnet/issues/298 ENV USER=argocd diff --git a/Gopkg.lock b/Gopkg.lock index 30d3846a987f0..86330a62bfa11 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -1652,9 +1652,11 @@ "gopkg.in/src-d/go-git.v4/config", "gopkg.in/src-d/go-git.v4/plumbing", "gopkg.in/src-d/go-git.v4/plumbing/transport", + "gopkg.in/src-d/go-git.v4/plumbing/transport/client", "gopkg.in/src-d/go-git.v4/plumbing/transport/http", "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh", "gopkg.in/src-d/go-git.v4/storage/memory", + "gopkg.in/src-d/go-git.v4/utils/ioutil", "gopkg.in/yaml.v2", "k8s.io/api/apps/v1", "k8s.io/api/batch/v1", diff --git a/assets/builtin-policy.csv b/assets/builtin-policy.csv index f0f4a32490021..a0351d6f90eec 100644 --- a/assets/builtin-policy.csv +++ b/assets/builtin-policy.csv @@ -7,6 +7,7 @@ # p, , , , p, role:readonly, applications, get, */*, allow +p, role:readonly, certificates, get, *, allow p, role:readonly, clusters, get, *, allow p, role:readonly, repositories, get, *, allow p, role:readonly, projects, get, *, allow @@ -16,6 +17,9 @@ p, role:admin, applications, update, */*, allow p, role:admin, applications, delete, */*, allow p, role:admin, applications, sync, */*, allow p, role:admin, applications, override, */*, allow +p, role:admin, certificates, create, *, allow +p, role:admin, certificates, update, *, allow +p, role:admin, certificates, delete, *, allow p, role:admin, clusters, create, *, allow p, role:admin, clusters, update, *, allow p, role:admin, clusters, delete, *, allow diff --git a/assets/swagger.json b/assets/swagger.json index ef236b553cb3b..f15e01110e1fa 100644 --- a/assets/swagger.json +++ b/assets/swagger.json @@ -49,7 +49,7 @@ "ApplicationService" ], "summary": "List returns list of applications", - "operationId": "ListMixin5", + "operationId": "ListMixin1", "parameters": [ { "type": "string", @@ -89,7 +89,7 @@ "ApplicationService" ], "summary": "Create creates an application", - "operationId": "CreateMixin5", + "operationId": "CreateMixin1", "parameters": [ { "name": "body", @@ -116,7 +116,7 @@ "ApplicationService" ], "summary": "Update updates an application", - "operationId": "UpdateMixin5", + "operationId": "UpdateMixin1", "parameters": [ { "type": "string", @@ -197,7 +197,7 @@ "ApplicationService" ], "summary": "Get returns an application by name", - "operationId": "GetMixin5", + "operationId": "Get", "parameters": [ { "type": "string", @@ -238,7 +238,7 @@ "ApplicationService" ], "summary": "Delete deletes an application", - "operationId": "DeleteMixin5", + "operationId": "DeleteMixin1", "parameters": [ { "type": "string", @@ -769,13 +769,89 @@ } } }, + "/api/v1/certificates": { + "get": { + "tags": [ + "CertificateService" + ], + "summary": "List all available certificates", + "operationId": "ListMixin2", + "parameters": [ + { + "type": "string", + "description": "A file-glob pattern (not regular expression) the host name has to match.", + "name": "hostNamePattern", + "in": "query" + }, + { + "type": "string", + "description": "The type of the certificate to match (ssh or https).", + "name": "certType", + "in": "query" + }, + { + "type": "string", + "description": "The sub type of the certificate to match (protocol dependent, usually only used for ssh certs).", + "name": "certSubType", + "in": "query" + } + ], + "responses": { + "200": { + "description": "(empty)", + "schema": { + "$ref": "#/definitions/v1alpha1RepositoryCertificateList" + } + } + } + }, + "post": { + "tags": [ + "CertificateService" + ], + "summary": "Creates the requested certificates on the server", + "operationId": "CreateMixin2", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1alpha1RepositoryCertificateList" + } + } + ], + "responses": { + "200": { + "description": "(empty)", + "schema": { + "$ref": "#/definitions/v1alpha1RepositoryCertificateList" + } + } + } + }, + "delete": { + "tags": [ + "CertificateService" + ], + "operationId": "DeleteMixin2", + "responses": { + "200": { + "description": "(empty)", + "schema": { + "$ref": "#/definitions/v1alpha1RepositoryCertificateList" + } + } + } + } + }, "/api/v1/clusters": { "get": { "tags": [ "ClusterService" ], "summary": "List returns list of clusters", - "operationId": "List", + "operationId": "ListMixin3", "parameters": [ { "type": "string", @@ -797,7 +873,7 @@ "ClusterService" ], "summary": "Create creates a cluster", - "operationId": "Create", + "operationId": "CreateMixin3", "parameters": [ { "name": "body", @@ -824,7 +900,7 @@ "ClusterService" ], "summary": "Update updates a cluster", - "operationId": "Update", + "operationId": "UpdateMixin3", "parameters": [ { "type": "string", @@ -857,7 +933,7 @@ "ClusterService" ], "summary": "Get returns a cluster by server address", - "operationId": "GetMixin1", + "operationId": "GetMixin3", "parameters": [ { "type": "string", @@ -880,7 +956,7 @@ "ClusterService" ], "summary": "Delete deletes a cluster", - "operationId": "Delete", + "operationId": "DeleteMixin3", "parameters": [ { "type": "string", @@ -930,7 +1006,7 @@ "ProjectService" ], "summary": "List returns list of projects", - "operationId": "ListMixin3", + "operationId": "ListMixin4", "parameters": [ { "type": "string", @@ -952,7 +1028,7 @@ "ProjectService" ], "summary": "Create a new project.", - "operationId": "CreateMixin3", + "operationId": "CreateMixin4", "parameters": [ { "name": "body", @@ -979,7 +1055,7 @@ "ProjectService" ], "summary": "Get returns a project by name", - "operationId": "GetMixin3", + "operationId": "GetMixin4", "parameters": [ { "type": "string", @@ -1002,7 +1078,7 @@ "ProjectService" ], "summary": "Delete deletes a project", - "operationId": "DeleteMixin3", + "operationId": "DeleteMixin4", "parameters": [ { "type": "string", @@ -1052,7 +1128,7 @@ "ProjectService" ], "summary": "Update updates a project", - "operationId": "UpdateMixin3", + "operationId": "UpdateMixin4", "parameters": [ { "type": "string", @@ -1162,7 +1238,7 @@ "RepositoryService" ], "summary": "List returns list of repos", - "operationId": "ListMixin2", + "operationId": "List", "parameters": [ { "type": "string", @@ -1184,7 +1260,7 @@ "RepositoryService" ], "summary": "Create creates a repo", - "operationId": "CreateMixin2", + "operationId": "Create", "parameters": [ { "name": "body", @@ -1211,7 +1287,7 @@ "RepositoryService" ], "summary": "Update updates a repo", - "operationId": "UpdateMixin2", + "operationId": "Update", "parameters": [ { "type": "string", @@ -1244,7 +1320,7 @@ "RepositoryService" ], "summary": "Delete deletes a repo", - "operationId": "DeleteMixin2", + "operationId": "Delete", "parameters": [ { "type": "string", @@ -1342,13 +1418,46 @@ } } }, + "/api/v1/repositories/{repo}/validate": { + "post": { + "tags": [ + "RepositoryService" + ], + "summary": "ValidateAccess validates access to a repository with given parameters", + "operationId": "ValidateAccess", + "parameters": [ + { + "type": "string", + "name": "repo", + "in": "path", + "required": true + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "(empty)", + "schema": { + "$ref": "#/definitions/repositoryRepoResponse" + } + } + } + } + }, "/api/v1/session": { "post": { "tags": [ "SessionService" ], "summary": "Create a new JWT for authentication and set a cookie if using HTTP.", - "operationId": "CreateMixin7", + "operationId": "CreateMixin8", "parameters": [ { "name": "body", @@ -1373,7 +1482,7 @@ "SessionService" ], "summary": "Delete an existing JWT cookie if using HTTP.", - "operationId": "DeleteMixin7", + "operationId": "DeleteMixin8", "responses": { "200": { "description": "(empty)", @@ -1390,7 +1499,7 @@ "SettingsService" ], "summary": "Get returns Argo CD settings", - "operationId": "Get", + "operationId": "GetMixin5", "responses": { "200": { "description": "(empty)", @@ -3145,21 +3254,74 @@ "connectionState": { "$ref": "#/definitions/v1alpha1ConnectionState" }, + "insecure": { + "type": "boolean", + "format": "boolean", + "title": "Whether the repo is insecure" + }, "insecureIgnoreHostKey": { "type": "boolean", - "format": "boolean" + "format": "boolean", + "title": "InsecureIgnoreHostKey should not be used anymore, Insecure is favoured" }, "password": { - "type": "string" + "type": "string", + "title": "Password for authenticating at the repo server" }, "repo": { - "type": "string" + "type": "string", + "title": "URL of the repo" }, "sshPrivateKey": { - "type": "string" + "type": "string", + "title": "SSH private key data for authenticating at the repo server" }, "username": { - "type": "string" + "type": "string", + "title": "Username for authenticating at the repo server" + } + } + }, + "v1alpha1RepositoryCertificate": { + "type": "object", + "title": "A RepositoryCertificate is either SSH known hosts entry or TLS certificate", + "properties": { + "certdata": { + "type": "string", + "format": "byte", + "title": "Actual certificate data, protocol dependent" + }, + "certfingerprint": { + "type": "string", + "title": "Certificate fingerprint" + }, + "cipher": { + "type": "string", + "title": "The sub type of the cert, i.e. \"ssh-rsa\"" + }, + "servername": { + "type": "string", + "title": "Name of the server the certificate is intended for" + }, + "type": { + "type": "string", + "title": "Type of certificate - currently \"https\" or \"ssh\"" + } + } + }, + "v1alpha1RepositoryCertificateList": { + "type": "object", + "title": "RepositoryCertificateList is a collection of RepositoryCertificates", + "properties": { + "items": { + "type": "array", + "title": "List of certificates to be processed", + "items": { + "$ref": "#/definitions/v1alpha1RepositoryCertificate" + } + }, + "metadata": { + "$ref": "#/definitions/v1ListMeta" } } }, diff --git a/cmd/argocd/commands/cert.go b/cmd/argocd/commands/cert.go new file mode 100644 index 0000000000000..567b0cecbff72 --- /dev/null +++ b/cmd/argocd/commands/cert.go @@ -0,0 +1,305 @@ +package commands + +import ( + "context" + "fmt" + "os" + "sort" + "strings" + "text/tabwriter" + + "github.com/spf13/cobra" + + "github.com/argoproj/argo-cd/errors" + argocdclient "github.com/argoproj/argo-cd/pkg/apiclient" + certificatepkg "github.com/argoproj/argo-cd/pkg/apiclient/certificate" + appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/util" + certutil "github.com/argoproj/argo-cd/util/cert" + + "crypto/x509" +) + +// NewCertCommand returns a new instance of an `argocd repo` command +func NewCertCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var command = &cobra.Command{ + Use: "cert", + Short: "Manage repository certificates and SSH known hosts entries", + Run: func(c *cobra.Command, args []string) { + c.HelpFunc()(c, args) + os.Exit(1) + }, + } + + command.AddCommand(NewCertAddSSHCommand(clientOpts)) + command.AddCommand(NewCertAddTLSCommand(clientOpts)) + command.AddCommand(NewCertListCommand(clientOpts)) + command.AddCommand(NewCertRemoveCommand(clientOpts)) + return command +} + +func NewCertAddTLSCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var ( + fromFile string + upsert bool + ) + var command = &cobra.Command{ + Use: "add-tls SERVERNAME", + Short: "Add TLS certificate data for connecting to repository server SERVERNAME", + Run: func(c *cobra.Command, args []string) { + conn, certIf := argocdclient.NewClientOrDie(clientOpts).NewCertClientOrDie() + defer util.Close(conn) + + if len(args) != 1 { + c.HelpFunc()(c, args) + os.Exit(1) + } + + var certificateArray []string + var err error + + if fromFile != "" { + fmt.Printf("Reading TLS certificate data in PEM format from '%s'\n", fromFile) + certificateArray, err = certutil.ParseTLSCertificatesFromPath(fromFile) + } else { + fmt.Println("Enter TLS certificate data in PEM format. Press CTRL-D when finished.") + certificateArray, err = certutil.ParseTLSCertificatesFromStream(os.Stdin) + } + + errors.CheckError(err) + + certificateList := make([]appsv1.RepositoryCertificate, 0) + + subjectMap := make(map[string]*x509.Certificate) + + for _, entry := range certificateArray { + // We want to make sure to only send valid certificate data to the + // server, so we decode the certificate into X509 structure before + // further processing it. + x509cert, err := certutil.DecodePEMCertificateToX509(entry) + errors.CheckError(err) + + // TODO: We need a better way to detect duplicates sent in the stream, + // maybe by using fingerprints? For now, no two certs with the same + // subject may be sent. + if subjectMap[x509cert.Subject.String()] != nil { + fmt.Printf("ERROR: Cert with subject '%s' already seen in the input stream.\n", x509cert.Subject.String()) + continue + } else { + subjectMap[x509cert.Subject.String()] = x509cert + } + } + + serverName := args[0] + + if len(certificateArray) > 0 { + certificateList = append(certificateList, appsv1.RepositoryCertificate{ + ServerName: serverName, + CertType: "https", + CertData: []byte(strings.Join(certificateArray, "\n")), + }) + certificates, err := certIf.Create(context.Background(), &certificatepkg.RepositoryCertificateCreateRequest{ + Certificates: &appsv1.RepositoryCertificateList{ + Items: certificateList, + }, + Upsert: upsert, + }) + errors.CheckError(err) + fmt.Printf("Created entry with %d PEM certificates for repository server %s\n", len(certificates.Items), serverName) + } else { + fmt.Printf("No valid certificates have been detected in the stream.\n") + } + }, + } + command.Flags().StringVar(&fromFile, "from", "", "read TLS certificate data from file (default is to read from stdin)") + command.Flags().BoolVar(&upsert, "upsert", false, "Replace existing TLS certificate if certificate is different in input") + return command +} + +// NewCertAddCommand returns a new instance of an `argocd cert add` command +func NewCertAddSSHCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var ( + fromFile string + batchProcess bool + upsert bool + certificates []appsv1.RepositoryCertificate + ) + + var command = &cobra.Command{ + Use: "add-ssh --batch", + Short: "Add SSH known host entries for repository servers", + Run: func(c *cobra.Command, args []string) { + + conn, certIf := argocdclient.NewClientOrDie(clientOpts).NewCertClientOrDie() + defer util.Close(conn) + + var sshKnownHostsLists []string + var err error + + // --batch is a flag, but it is mandatory for now. + if batchProcess { + if fromFile != "" { + fmt.Printf("Reading SSH known hosts entries from file '%s'\n", fromFile) + sshKnownHostsLists, err = certutil.ParseSSHKnownHostsFromPath(fromFile) + } else { + fmt.Println("Enter SSH known hosts entries, one per line. Press CTRL-D when finished.") + sshKnownHostsLists, err = certutil.ParseSSHKnownHostsFromStream(os.Stdin) + } + } else { + err = fmt.Errorf("You need to specify --batch or specify --help for usage instructions") + } + + errors.CheckError(err) + + if len(sshKnownHostsLists) == 0 { + errors.CheckError(fmt.Errorf("No valid SSH known hosts data found.")) + } + + for _, knownHostsEntry := range sshKnownHostsLists { + hostname, certSubType, certData, err := certutil.TokenizeSSHKnownHostsEntry(knownHostsEntry) + errors.CheckError(err) + _, _, err = certutil.KnownHostsLineToPublicKey(knownHostsEntry) + errors.CheckError(err) + certificate := appsv1.RepositoryCertificate{ + ServerName: hostname, + CertType: "ssh", + CertSubType: certSubType, + CertData: certData, + } + + certificates = append(certificates, certificate) + } + + certList := &appsv1.RepositoryCertificateList{Items: certificates} + response, err := certIf.Create(context.Background(), &certificatepkg.RepositoryCertificateCreateRequest{ + Certificates: certList, + Upsert: upsert, + }) + errors.CheckError(err) + fmt.Printf("Successfully created %d SSH known host entries\n", len(response.Items)) + }, + } + command.Flags().StringVar(&fromFile, "from", "", "Read SSH known hosts data from file (default is to read from stdin)") + command.Flags().BoolVar(&batchProcess, "batch", false, "Perform batch processing by reading in SSH known hosts data (mandatory flag)") + command.Flags().BoolVar(&upsert, "upsert", false, "Replace existing SSH server public host keys if key is different in input") + return command +} + +// NewCertRemoveCommand returns a new instance of an `argocd cert rm` command +func NewCertRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var ( + removeAllCerts bool + certType string + certSubType string + certQuery certificatepkg.RepositoryCertificateQuery + ) + var command = &cobra.Command{ + Use: "rm REPOSERVER", + Short: "Remove certificate of TYPE for REPOSERVER", + Run: func(c *cobra.Command, args []string) { + if len(args) < 1 && !removeAllCerts { + c.HelpFunc()(c, args) + os.Exit(1) + } + conn, certIf := argocdclient.NewClientOrDie(clientOpts).NewCertClientOrDie() + defer util.Close(conn) + if removeAllCerts { + certQuery = certificatepkg.RepositoryCertificateQuery{ + HostNamePattern: "*", + CertType: "*", + CertSubType: "*", + } + } else { + certQuery = certificatepkg.RepositoryCertificateQuery{ + HostNamePattern: args[0], + CertType: certType, + CertSubType: certSubType, + } + } + removed, err := certIf.Delete(context.Background(), &certQuery) + errors.CheckError(err) + if len(removed.Items) > 0 { + for _, cert := range removed.Items { + fmt.Printf("Removed cert for '%s' of type '%s' (subtype '%s')\n", cert.ServerName, cert.CertType, cert.CertSubType) + } + } else { + fmt.Println("No certificates were removed (none matched the given patterns)") + } + }, + } + command.Flags().BoolVar(&removeAllCerts, "remove-all", false, "Remove all configured certificates of all types from server (DANGER: use with care!)") + command.Flags().StringVar(&certType, "cert-type", "", "Only remove certs of given type (ssh, https)") + command.Flags().StringVar(&certSubType, "cert-sub-type", "", "Only remove certs of given sub-type (only for ssh)") + return command +} + +// NewCertListCommand returns a new instance of an `argocd cert rm` command +func NewCertListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var ( + certType string + hostNamePattern string + sortOrder string + ) + var command = &cobra.Command{ + Use: "list", + Short: "List configured certificates", + Run: func(c *cobra.Command, args []string) { + if certType != "" { + switch certType { + case "ssh": + case "https": + default: + fmt.Println("cert-type must be either ssh or https") + os.Exit(1) + } + } + + conn, certIf := argocdclient.NewClientOrDie(clientOpts).NewCertClientOrDie() + defer util.Close(conn) + certificates, err := certIf.List(context.Background(), &certificatepkg.RepositoryCertificateQuery{HostNamePattern: hostNamePattern, CertType: certType}) + errors.CheckError(err) + printCertTable(certificates.Items, sortOrder) + }, + } + + command.Flags().StringVar(&sortOrder, "sort", "", "set display sort order, valid: 'hostname', 'type'") + command.Flags().StringVar(&certType, "cert-type", "", "only list certificates of given type, valid: 'ssh','https'") + command.Flags().StringVar(&hostNamePattern, "hostname-pattern", "", "only list certificates for hosts matching given glob-pattern") + return command +} + +// Print table of certificate info +func printCertTable(certs []appsv1.RepositoryCertificate, sortOrder string) { + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + fmt.Fprintf(w, "HOSTNAME\tTYPE\tSUBTYPE\tFINGERPRINT/SUBJECT\n") + + if sortOrder == "hostname" || sortOrder == "" { + sort.Slice(certs, func(i, j int) bool { + return certs[i].ServerName < certs[j].ServerName + }) + } else if sortOrder == "type" { + sort.Slice(certs, func(i, j int) bool { + return certs[i].CertType < certs[j].CertType + }) + } + + for _, c := range certs { + if c.CertType == "ssh" { + _, pubKey, err := certutil.TokenizedDataToPublicKey(c.ServerName, c.CertSubType, string(c.CertData)) + errors.CheckError(err) + fmt.Fprintf(w, "%s\t%s\t%s\tSHA256:%s\n", c.ServerName, c.CertType, c.CertSubType, certutil.SSHFingerprintSHA256(pubKey)) + } else if c.CertType == "https" { + x509Data, err := certutil.DecodePEMCertificateToX509(string(c.CertData)) + var subject string + keyType := "-?-" + if err != nil { + subject = err.Error() + } else { + subject = x509Data.Subject.String() + keyType = x509Data.PublicKeyAlgorithm.String() + } + fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", c.ServerName, c.CertType, strings.ToLower(keyType), subject) + } + } + _ = w.Flush() +} diff --git a/cmd/argocd/commands/repo.go b/cmd/argocd/commands/repo.go index 83c087e6bdb33..c0ab07d031078 100644 --- a/cmd/argocd/commands/repo.go +++ b/cmd/argocd/commands/repo.go @@ -16,7 +16,6 @@ import ( appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/util" "github.com/argoproj/argo-cd/util/cli" - "github.com/argoproj/argo-cd/util/git" ) // NewRepoCommand returns a new instance of an `argocd repo` command @@ -39,10 +38,11 @@ func NewRepoCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { // NewRepoAddCommand returns a new instance of an `argocd repo add` command func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - repo appsv1.Repository - upsert bool - sshPrivateKeyPath string - insecureIgnoreHostKey bool + repo appsv1.Repository + upsert bool + sshPrivateKeyPath string + insecureIgnoreHostKey bool + insecureSkipServerVerification bool ) var command = &cobra.Command{ Use: "add REPO", @@ -60,24 +60,32 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { } repo.SSHPrivateKey = string(keyData) } + // InsecureIgnoreHostKey is deprecated and only here for backwards compat repo.InsecureIgnoreHostKey = insecureIgnoreHostKey - // First test the repo *without* username/password. This gives us a hint on whether this - // is a private repo. - // NOTE: it is important not to run git commands to test git credentials on the user's - // system since it may mess with their git credential store (e.g. osx keychain). - // See issue #315 - err := git.TestRepo(repo.Repo, "", "", repo.SSHPrivateKey, repo.InsecureIgnoreHostKey) - if err != nil { - if yes, _ := git.IsSSHURL(repo.Repo); yes { - // If we failed using git SSH credentials, then the repo is automatically bad - log.Fatal(err) - } - // If we can't test the repo, it's probably private. Prompt for credentials and - // let the server test it. - repo.Username, repo.Password = cli.PromptCredentials(repo.Username, repo.Password) - } + repo.Insecure = insecureSkipServerVerification + conn, repoIf := argocdclient.NewClientOrDie(clientOpts).NewRepoClientOrDie() defer util.Close(conn) + + // If the user set a username, but didn't supply password via --password, + // then we prompt for it + if repo.Username != "" && repo.Password == "" { + repo.Password = cli.PromptPassword(repo.Password) + } + + // We let the server check access to the repository before adding it. If + // it is a private repo, but we cannot access with with the credentials + // that were supplied, we bail out. + repoAccessReq := repositorypkg.RepoAccessQuery{ + Repo: repo.Repo, + Username: repo.Username, + Password: repo.Password, + SshPrivateKey: repo.SSHPrivateKey, + Insecure: (repo.InsecureIgnoreHostKey || repo.Insecure), + } + _, err := repoIf.ValidateAccess(context.Background(), &repoAccessReq) + errors.CheckError(err) + repoCreateReq := repositorypkg.RepoCreateRequest{ Repo: &repo, Upsert: upsert, @@ -90,7 +98,8 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { command.Flags().StringVar(&repo.Username, "username", "", "username to the repository") command.Flags().StringVar(&repo.Password, "password", "", "password to the repository") command.Flags().StringVar(&sshPrivateKeyPath, "ssh-private-key-path", "", "path to the private ssh key (e.g. ~/.ssh/id_rsa)") - command.Flags().BoolVar(&insecureIgnoreHostKey, "insecure-ignore-host-key", false, "disables SSH strict host key checking") + command.Flags().BoolVar(&insecureIgnoreHostKey, "insecure-ignore-host-key", false, "disables SSH strict host key checking (deprecated, use --insecure-skip-server-validation instead)") + command.Flags().BoolVar(&insecureSkipServerVerification, "insecure-skip-server-verification", false, "disables server certificate and host key checks") command.Flags().BoolVar(&upsert, "upsert", false, "Override an existing repository with the same name even if the spec differs") return command } @@ -119,9 +128,15 @@ func NewRepoRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command // Print table of repo info func printRepoTable(repos []appsv1.Repository) { w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) - fmt.Fprintf(w, "REPO\tUSER\tSTATUS\tMESSAGE\n") + fmt.Fprintf(w, "REPO\tINSECURE\tUSER\tSTATUS\tMESSAGE\n") for _, r := range repos { - fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", r.Repo, r.Username, r.ConnectionState.Status, r.ConnectionState.Message) + var username string + if r.Username == "" { + username = "-" + } else { + username = r.Username + } + fmt.Fprintf(w, "%s\t%v\t%s\t%s\t%s\n", r.Repo, r.Insecure, username, r.ConnectionState.Status, r.ConnectionState.Message) } _ = w.Flush() } diff --git a/cmd/argocd/commands/root.go b/cmd/argocd/commands/root.go index 22fc58970155a..d1978cc19c59d 100644 --- a/cmd/argocd/commands/root.go +++ b/cmd/argocd/commands/root.go @@ -47,6 +47,7 @@ func NewCommand() *cobra.Command { command.AddCommand(NewProjectCommand(&clientOpts)) command.AddCommand(NewAccountCommand(&clientOpts)) command.AddCommand(NewLogoutCommand(&clientOpts)) + command.AddCommand(NewCertCommand(&clientOpts)) defaultLocalConfigPath, err := localconfig.DefaultLocalConfigPath() errors.CheckError(err) diff --git a/common/common.go b/common/common.go index 0b02807c29ba8..4b13a1be3e8b2 100644 --- a/common/common.go +++ b/common/common.go @@ -15,6 +15,10 @@ const ( ArgoCDConfigMapName = "argocd-cm" ArgoCDSecretName = "argocd-secret" ArgoCDRBACConfigMapName = "argocd-rbac-cm" + // Contains SSH known hosts data for connecting repositories. Will get mounted as volume to pods + ArgoCDKnownHostsConfigMapName = "argocd-ssh-known-hosts-cm" + // Contains TLS certificate data for connecting repositories. Will get mounted as volume to pods + ArgoCDTLSCertsConfigMapName = "argocd-tls-certs-cm" ) // Default system namespace diff --git a/controller/appcontroller_test.go b/controller/appcontroller_test.go index f8fbc517cf9f8..a2bae95f490fb 100644 --- a/controller/appcontroller_test.go +++ b/controller/appcontroller_test.go @@ -64,6 +64,9 @@ func newFakeController(data *fakeData) *ApplicationController { ObjectMeta: metav1.ObjectMeta{ Name: "argocd-cm", Namespace: test.FakeArgoCDNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: nil, } diff --git a/docs/user-guide/private-repositories.md b/docs/user-guide/private-repositories.md index 1bac079937798..7da8ed845114e 100644 --- a/docs/user-guide/private-repositories.md +++ b/docs/user-guide/private-repositories.md @@ -43,6 +43,54 @@ argocd repo add git@github.com:argoproj/argocd-example-apps.git --ssh-private-ke ## Self-signed & Untrusted TLS Certificates +> v1.2 or higher + +If you are connecting a repository on a HTTPS server using a self-signed certificate, or a certificate signed by a custom Certificate Authority (CA) which are not known to ArgoCD, the repository will not be added due to security reasons. This is indicated by an error message such as `x509: certificate signed by unknown authority`. + +1. You can let ArgoCD connect the repository in an insecure way, without verifying the server's certificate at all. This can be accomplished by using the `--insecure-repository` flag when adding the repository with the `argocd` CLI utility. However, this should be done only for non-production setups, as it imposes a serious security issue through possible man-in-the-middle attacks. + +2. You can let ArgoCD use a custom certificate for the verification of the server's certificate using the `cert add-tls` command of the `argocd` CLI utility. This is the recommended method and suitable for production use. In order to do so, you will need the server's certificate, or the certificate of the CA used to sign the server's certificate, in PEM format. + +!!! note + For invalid server certificates, such as those without matching server name, or those that are expired, adding a CA certificate will not help. In this case, your only option will be to use the `--insecure-repository` flag to connect the repository. You are strongly urged to use a valid certificate on the repository server, or to urge the server's administrator to replace the faulty certificate with a valid one. + +Example for adding a HTTPS repository to ArgoCD without verifying the server's certificate (**Caution:** This is **not** recommended for production use): + +```bash +argocd repo add --insecure-repository https://git.example.com/test-repo +``` + +Example for adding a CA certificate contained in file `~/myca-cert.pem` to properly verify the repository server: + +```bash +argocd cert add-tls git.example.com --from ~/myca-cert.pem +argocd repo add https://git.example.com/test-repo +``` + +You can also add more than one PEM for a server by concatenating them into the input stream. This might be useful if the repository server is about to replace the server certificate, possibly with one signed by a different CA. This way, you can have the old (current) as well as the new (future) certificate co-existing. If you already have the old certificate configured, use the `--upsert` flag and add the old and the new one in a single run: + +```bash +cat cert1.pem cert2.pem | argocd cert add-tls git.example.com --upsert +``` + +!!! note + You can add multiple TLS certificates for a single server by either using a file containing multiple PEM certificates, or by using the `--append` flag to the `cert add-tls` command of the CLI. + +!!! note + To replace an existing certificate for a server, use the `--upsert` flag to the `cert add-tls` CLI command. + +!!! note + TLS certificates are configured on a per-server, not on a per-repository basis. If you connect multiple repositories from the same server, you only have to configure the certificates once for this server. + +!!! note + It can take up to a couple of minutes until the changes performed by the `argocd cert` command are propagated across your cluster, depending on your Kubernetes setup. + +You can also manage TLS certificates in a declarative, self-managed ArgoCD setup. All TLS certificates are stored in the ConfigMap object `argocd-tls-cert-cm`. + +Managing TLS certificates via the web UI is currently not possible. + +> Before v1.2 + We do not currently have first-class support for this. See [#1513](https://github.com/argoproj/argo-cd/issues/1513). As a work-around, you can customize your Argo CD image. See [#1344](https://github.com/argoproj/argo-cd/issues/1344#issuecomment-479811810) @@ -50,6 +98,35 @@ As a work-around, you can customize your Argo CD image. See [#1344](https://gith ## Unknown SSH Hosts If you are using a privately hosted Git service over SSH, then you have the following options: + +> v1.2 or later + +1. You can let ArgoCD connect the repository in an insecure way, without verifying the server's SSH host key at all. This can be accomplished by using the `--insecure-repository` flag when adding the repository with the `argocd` CLI utility. However, this should be done only for non-production setups, as it imposes a serious security issue through possible man-in-the-middle attacks. + +2. You can make the server's SSH public key known to ArgoCD by using the `cert add-ssh` command of the `argocd` CLI utility. This is the recommended method and suitable for production use. In order to do so, you will need the server's SSH public host key, in the `known_hosts` format understood by `ssh`. You can get the server's public SSH host key e.g. by using the `ssh-keyscan` utility. + +Example for adding all available SSH public host keys for a server to ArgoCD: + +```bash +ssh-keyscan server.example.com | argocd cert add-ssh --batch + +``` + +Example for importing an existing `known_hosts` file to ArgoCD: + +```bash +argocd cert add-ssh --batch --from /etc/ssh/ssh_known_hosts +``` + +!!! note + It can take up to a couple of minutes until the changes performed by the `argocd cert` command are propagated across your cluster, depending on your Kubernetes setup. + +You can also manage SSH known hosts entries in a declarative, self-managed ArgoCD setup. All SSH public host keys are stored in the ConfigMap object `argocd-ssh-known-hosts-cm`. + +Managing SSH public host keys via the web UI is currently not possible. + +> Before v1.2 + (1) You can customize the Argo CD Docker image by adding the host's SSH public key to `/etc/ssh/ssh_known_hosts`. Additional entries to this file can be generated using the `ssh-keyscan` utility (e.g. `ssh-keyscan your-private-git-server.com`. For more information see [example](https://github.com/argoproj/argo-cd/tree/master/examples/known-hosts) which demonstrates how `/etc/ssh/ssh_known_hosts` can be customized. @@ -71,5 +148,5 @@ argocd repo add git@github.com:argoproj/argocd-example-apps.git --ssh-private-ke ## Declarative Configuration -See [declarative setup](../operator-manual/declarative-setup#Repositories) +See [declarative setup](../../operator-manual/declarative-setup#Repositories) diff --git a/hack/generate-proto.sh b/hack/generate-proto.sh index 9de177c1fec07..41153f4585550 100755 --- a/hack/generate-proto.sh +++ b/hack/generate-proto.sh @@ -121,7 +121,7 @@ clean_swagger() { /usr/bin/find "${SWAGGER_ROOT}" -name '*.swagger.json' -delete } -collect_swagger server 26 +collect_swagger server 27 clean_swagger server clean_swagger reposerver clean_swagger controller diff --git a/manifests/base/config/argocd-ssh-known-hosts-cm.yaml b/manifests/base/config/argocd-ssh-known-hosts-cm.yaml new file mode 100644 index 0000000000000..7f129a142836e --- /dev/null +++ b/manifests/base/config/argocd-ssh-known-hosts-cm.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-ssh-known-hosts-cm + app.kubernetes.io/part-of: argocd + name: argocd-ssh-known-hosts-cm +data: + 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= + gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf + 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 diff --git a/manifests/base/config/argocd-tls-certs-cm.yaml b/manifests/base/config/argocd-tls-certs-cm.yaml new file mode 100644 index 0000000000000..4f1e55d344325 --- /dev/null +++ b/manifests/base/config/argocd-tls-certs-cm.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-tls-certs-cm + app.kubernetes.io/part-of: argocd + name: argocd-tls-certs-cm +data: \ No newline at end of file diff --git a/manifests/base/config/kustomization.yaml b/manifests/base/config/kustomization.yaml index 5df106fce42f9..124f2d00120e4 100644 --- a/manifests/base/config/kustomization.yaml +++ b/manifests/base/config/kustomization.yaml @@ -4,4 +4,6 @@ kind: Kustomization resources: - argocd-cm.yaml - argocd-secret.yaml -- argocd-rbac-cm.yaml \ No newline at end of file +- argocd-rbac-cm.yaml +- argocd-ssh-known-hosts-cm.yaml +- argocd-tls-certs-cm.yaml diff --git a/manifests/base/repo-server/argocd-repo-server-deployment.yaml b/manifests/base/repo-server/argocd-repo-server-deployment.yaml index b7b0a1ad9c01c..d9057cea44f11 100644 --- a/manifests/base/repo-server/argocd-repo-server-deployment.yaml +++ b/manifests/base/repo-server/argocd-repo-server-deployment.yaml @@ -37,3 +37,15 @@ spec: port: 8081 initialDelaySeconds: 5 periodSeconds: 10 + volumeMounts: + - name: ssh-known-hosts + mountPath: /app/config/ssh + - name: tls-certs + mountPath: /app/config/tls + volumes: + - name: ssh-known-hosts + configMap: + name: argocd-ssh-known-hosts-cm + - name: tls-certs + configMap: + name: argocd-tls-certs-cm diff --git a/manifests/base/server/argocd-server-deployment.yaml b/manifests/base/server/argocd-server-deployment.yaml index 00d2d11e9f616..e537ef9c59354 100644 --- a/manifests/base/server/argocd-server-deployment.yaml +++ b/manifests/base/server/argocd-server-deployment.yaml @@ -32,6 +32,10 @@ spec: volumeMounts: - mountPath: /shared name: static-files + - name: ssh-known-hosts + mountPath: /app/config/ssh + - name: tls-certs + mountPath: /app/config/tls ports: - containerPort: 8080 - containerPort: 8083 @@ -50,3 +54,9 @@ spec: volumes: - emptyDir: {} name: static-files + - name: ssh-known-hosts + configMap: + name: argocd-ssh-known-hosts-cm + - name: tls-certs + configMap: + name: argocd-tls-certs-cm diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml index 7762c935376b1..b42aa952b300e 100644 --- a/manifests/ha/install.yaml +++ b/manifests/ha/install.yaml @@ -2720,6 +2720,32 @@ metadata: name: argocd-redis-ha-probes --- apiVersion: v1 +data: + 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= + gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf + 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 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-ssh-known-hosts-cm + app.kubernetes.io/part-of: argocd + name: argocd-ssh-known-hosts-cm +--- +apiVersion: v1 +data: null +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-tls-certs-cm + app.kubernetes.io/part-of: argocd + name: argocd-tls-certs-cm +--- +apiVersion: v1 kind: Secret metadata: labels: @@ -3086,6 +3112,18 @@ spec: periodSeconds: 10 tcpSocket: port: 8081 + volumeMounts: + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs + volumes: + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs --- apiVersion: apps/v1 kind: Deployment @@ -3153,6 +3191,10 @@ spec: volumeMounts: - mountPath: /shared name: static-files + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs initContainers: - command: - cp @@ -3169,6 +3211,12 @@ spec: volumes: - emptyDir: {} name: static-files + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs --- apiVersion: apps/v1 kind: StatefulSet diff --git a/manifests/ha/namespace-install.yaml b/manifests/ha/namespace-install.yaml index 40aa1d80ce7ce..8f7b6d530d53d 100644 --- a/manifests/ha/namespace-install.yaml +++ b/manifests/ha/namespace-install.yaml @@ -2635,6 +2635,32 @@ metadata: name: argocd-redis-ha-probes --- apiVersion: v1 +data: + 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= + gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf + 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 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-ssh-known-hosts-cm + app.kubernetes.io/part-of: argocd + name: argocd-ssh-known-hosts-cm +--- +apiVersion: v1 +data: null +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-tls-certs-cm + app.kubernetes.io/part-of: argocd + name: argocd-tls-certs-cm +--- +apiVersion: v1 kind: Secret metadata: labels: @@ -3001,6 +3027,18 @@ spec: periodSeconds: 10 tcpSocket: port: 8081 + volumeMounts: + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs + volumes: + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs --- apiVersion: apps/v1 kind: Deployment @@ -3068,6 +3106,10 @@ spec: volumeMounts: - mountPath: /shared name: static-files + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs initContainers: - command: - cp @@ -3084,6 +3126,12 @@ spec: volumes: - emptyDir: {} name: static-files + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs --- apiVersion: apps/v1 kind: StatefulSet diff --git a/manifests/install.yaml b/manifests/install.yaml index a0e792474a017..da3d612638f9e 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2578,6 +2578,32 @@ metadata: name: argocd-rbac-cm --- apiVersion: v1 +data: + 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= + gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf + 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 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-ssh-known-hosts-cm + app.kubernetes.io/part-of: argocd + name: argocd-ssh-known-hosts-cm +--- +apiVersion: v1 +data: null +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-tls-certs-cm + app.kubernetes.io/part-of: argocd + name: argocd-tls-certs-cm +--- +apiVersion: v1 kind: Secret metadata: labels: @@ -2858,6 +2884,18 @@ spec: periodSeconds: 10 tcpSocket: port: 8081 + volumeMounts: + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs + volumes: + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs --- apiVersion: apps/v1 kind: Deployment @@ -2902,6 +2940,10 @@ spec: volumeMounts: - mountPath: /shared name: static-files + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs initContainers: - command: - cp @@ -2918,3 +2960,9 @@ spec: volumes: - emptyDir: {} name: static-files + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 5fab8b9922b80..597410c9111b1 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -2493,6 +2493,32 @@ metadata: name: argocd-rbac-cm --- apiVersion: v1 +data: + 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= + gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf + 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 +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-ssh-known-hosts-cm + app.kubernetes.io/part-of: argocd + name: argocd-ssh-known-hosts-cm +--- +apiVersion: v1 +data: null +kind: ConfigMap +metadata: + labels: + app.kubernetes.io/name: argocd-tls-certs-cm + app.kubernetes.io/part-of: argocd + name: argocd-tls-certs-cm +--- +apiVersion: v1 kind: Secret metadata: labels: @@ -2773,6 +2799,18 @@ spec: periodSeconds: 10 tcpSocket: port: 8081 + volumeMounts: + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs + volumes: + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs --- apiVersion: apps/v1 kind: Deployment @@ -2817,6 +2855,10 @@ spec: volumeMounts: - mountPath: /shared name: static-files + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs initContainers: - command: - cp @@ -2833,3 +2875,9 @@ spec: volumes: - emptyDir: {} name: static-files + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs diff --git a/pkg/apiclient/apiclient.go b/pkg/apiclient/apiclient.go index 0892ad5ea721c..2fb5678078e65 100644 --- a/pkg/apiclient/apiclient.go +++ b/pkg/apiclient/apiclient.go @@ -27,6 +27,7 @@ import ( "github.com/argoproj/argo-cd/common" accountpkg "github.com/argoproj/argo-cd/pkg/apiclient/account" applicationpkg "github.com/argoproj/argo-cd/pkg/apiclient/application" + certificatepkg "github.com/argoproj/argo-cd/pkg/apiclient/certificate" clusterpkg "github.com/argoproj/argo-cd/pkg/apiclient/cluster" projectpkg "github.com/argoproj/argo-cd/pkg/apiclient/project" repositorypkg "github.com/argoproj/argo-cd/pkg/apiclient/repository" @@ -58,6 +59,8 @@ type Client interface { OIDCConfig(context.Context, *settingspkg.Settings) (*oauth2.Config, *oidc.Provider, error) NewRepoClient() (io.Closer, repositorypkg.RepositoryServiceClient, error) NewRepoClientOrDie() (io.Closer, repositorypkg.RepositoryServiceClient) + NewCertClient() (io.Closer, certificatepkg.CertificateServiceClient, error) + NewCertClientOrDie() (io.Closer, certificatepkg.CertificateServiceClient) NewClusterClient() (io.Closer, clusterpkg.ClusterServiceClient, error) NewClusterClientOrDie() (io.Closer, clusterpkg.ClusterServiceClient) NewApplicationClient() (io.Closer, applicationpkg.ApplicationServiceClient, error) @@ -437,6 +440,23 @@ func (c *client) NewRepoClientOrDie() (io.Closer, repositorypkg.RepositoryServic return conn, repoIf } +func (c *client) NewCertClient() (io.Closer, certificatepkg.CertificateServiceClient, error) { + conn, closer, err := c.newConn() + if err != nil { + return nil, nil, err + } + certIf := certificatepkg.NewCertificateServiceClient(conn) + return closer, certIf, nil +} + +func (c *client) NewCertClientOrDie() (io.Closer, certificatepkg.CertificateServiceClient) { + conn, certIf, err := c.NewCertClient() + if err != nil { + log.Fatalf("Failed to establish connection to %s: %v", c.ServerAddr, err) + } + return conn, certIf +} + func (c *client) NewClusterClient() (io.Closer, clusterpkg.ClusterServiceClient, error) { conn, closer, err := c.newConn() if err != nil { diff --git a/pkg/apiclient/certificate/certificate.pb.go b/pkg/apiclient/certificate/certificate.pb.go new file mode 100644 index 0000000000000..f63046d36bc01 --- /dev/null +++ b/pkg/apiclient/certificate/certificate.pb.go @@ -0,0 +1,949 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: server/certificate/certificate.proto + +package certificate // import "github.com/argoproj/argo-cd/pkg/apiclient/certificate" + +/* + Certificate Service + + Certificate Service API performs CRUD actions against repository certificate + resources. +*/ + +import proto "github.com/gogo/protobuf/proto" +import fmt "fmt" +import math "math" +import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1" +import _ "github.com/gogo/protobuf/gogoproto" +import _ "google.golang.org/genproto/googleapis/api/annotations" + +import context "golang.org/x/net/context" +import grpc "google.golang.org/grpc" + +import io "io" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package + +// Message to query the server for configured repository certificates +type RepositoryCertificateQuery struct { + // A file-glob pattern (not regular expression) the host name has to match + HostNamePattern string `protobuf:"bytes,1,opt,name=hostNamePattern,proto3" json:"hostNamePattern,omitempty"` + // The type of the certificate to match (ssh or https) + CertType string `protobuf:"bytes,2,opt,name=certType,proto3" json:"certType,omitempty"` + // The sub type of the certificate to match (protocol dependent, usually only used for ssh certs) + CertSubType string `protobuf:"bytes,3,opt,name=certSubType,proto3" json:"certSubType,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RepositoryCertificateQuery) Reset() { *m = RepositoryCertificateQuery{} } +func (m *RepositoryCertificateQuery) String() string { return proto.CompactTextString(m) } +func (*RepositoryCertificateQuery) ProtoMessage() {} +func (*RepositoryCertificateQuery) Descriptor() ([]byte, []int) { + return fileDescriptor_certificate_7cceab803f50bba4, []int{0} +} +func (m *RepositoryCertificateQuery) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RepositoryCertificateQuery) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RepositoryCertificateQuery.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *RepositoryCertificateQuery) XXX_Merge(src proto.Message) { + xxx_messageInfo_RepositoryCertificateQuery.Merge(dst, src) +} +func (m *RepositoryCertificateQuery) XXX_Size() int { + return m.Size() +} +func (m *RepositoryCertificateQuery) XXX_DiscardUnknown() { + xxx_messageInfo_RepositoryCertificateQuery.DiscardUnknown(m) +} + +var xxx_messageInfo_RepositoryCertificateQuery proto.InternalMessageInfo + +func (m *RepositoryCertificateQuery) GetHostNamePattern() string { + if m != nil { + return m.HostNamePattern + } + return "" +} + +func (m *RepositoryCertificateQuery) GetCertType() string { + if m != nil { + return m.CertType + } + return "" +} + +func (m *RepositoryCertificateQuery) GetCertSubType() string { + if m != nil { + return m.CertSubType + } + return "" +} + +// Request to create a set of certificates +type RepositoryCertificateCreateRequest struct { + // List of certificates to be created + Certificates *v1alpha1.RepositoryCertificateList `protobuf:"bytes,1,opt,name=certificates" json:"certificates,omitempty"` + // Whether to upsert already existing certificates + Upsert bool `protobuf:"varint,2,opt,name=upsert,proto3" json:"upsert,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RepositoryCertificateCreateRequest) Reset() { *m = RepositoryCertificateCreateRequest{} } +func (m *RepositoryCertificateCreateRequest) String() string { return proto.CompactTextString(m) } +func (*RepositoryCertificateCreateRequest) ProtoMessage() {} +func (*RepositoryCertificateCreateRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_certificate_7cceab803f50bba4, []int{1} +} +func (m *RepositoryCertificateCreateRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RepositoryCertificateCreateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RepositoryCertificateCreateRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *RepositoryCertificateCreateRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RepositoryCertificateCreateRequest.Merge(dst, src) +} +func (m *RepositoryCertificateCreateRequest) XXX_Size() int { + return m.Size() +} +func (m *RepositoryCertificateCreateRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RepositoryCertificateCreateRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RepositoryCertificateCreateRequest proto.InternalMessageInfo + +func (m *RepositoryCertificateCreateRequest) GetCertificates() *v1alpha1.RepositoryCertificateList { + if m != nil { + return m.Certificates + } + return nil +} + +func (m *RepositoryCertificateCreateRequest) GetUpsert() bool { + if m != nil { + return m.Upsert + } + return false +} + +type RepositoryCertificateResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RepositoryCertificateResponse) Reset() { *m = RepositoryCertificateResponse{} } +func (m *RepositoryCertificateResponse) String() string { return proto.CompactTextString(m) } +func (*RepositoryCertificateResponse) ProtoMessage() {} +func (*RepositoryCertificateResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_certificate_7cceab803f50bba4, []int{2} +} +func (m *RepositoryCertificateResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RepositoryCertificateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RepositoryCertificateResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *RepositoryCertificateResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RepositoryCertificateResponse.Merge(dst, src) +} +func (m *RepositoryCertificateResponse) XXX_Size() int { + return m.Size() +} +func (m *RepositoryCertificateResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RepositoryCertificateResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RepositoryCertificateResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*RepositoryCertificateQuery)(nil), "certificate.RepositoryCertificateQuery") + proto.RegisterType((*RepositoryCertificateCreateRequest)(nil), "certificate.RepositoryCertificateCreateRequest") + proto.RegisterType((*RepositoryCertificateResponse)(nil), "certificate.RepositoryCertificateResponse") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for CertificateService service + +type CertificateServiceClient interface { + // List all available certificates + List(ctx context.Context, in *RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) + // Creates the requested certificates on the server + Create(ctx context.Context, in *RepositoryCertificateCreateRequest, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) + Delete(ctx context.Context, in *RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) +} + +type certificateServiceClient struct { + cc *grpc.ClientConn +} + +func NewCertificateServiceClient(cc *grpc.ClientConn) CertificateServiceClient { + return &certificateServiceClient{cc} +} + +func (c *certificateServiceClient) List(ctx context.Context, in *RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) { + out := new(v1alpha1.RepositoryCertificateList) + err := c.cc.Invoke(ctx, "/certificate.CertificateService/List", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *certificateServiceClient) Create(ctx context.Context, in *RepositoryCertificateCreateRequest, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) { + out := new(v1alpha1.RepositoryCertificateList) + err := c.cc.Invoke(ctx, "/certificate.CertificateService/Create", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *certificateServiceClient) Delete(ctx context.Context, in *RepositoryCertificateQuery, opts ...grpc.CallOption) (*v1alpha1.RepositoryCertificateList, error) { + out := new(v1alpha1.RepositoryCertificateList) + err := c.cc.Invoke(ctx, "/certificate.CertificateService/Delete", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for CertificateService service + +type CertificateServiceServer interface { + // List all available certificates + List(context.Context, *RepositoryCertificateQuery) (*v1alpha1.RepositoryCertificateList, error) + // Creates the requested certificates on the server + Create(context.Context, *RepositoryCertificateCreateRequest) (*v1alpha1.RepositoryCertificateList, error) + Delete(context.Context, *RepositoryCertificateQuery) (*v1alpha1.RepositoryCertificateList, error) +} + +func RegisterCertificateServiceServer(s *grpc.Server, srv CertificateServiceServer) { + s.RegisterService(&_CertificateService_serviceDesc, srv) +} + +func _CertificateService_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RepositoryCertificateQuery) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CertificateServiceServer).List(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/certificate.CertificateService/List", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CertificateServiceServer).List(ctx, req.(*RepositoryCertificateQuery)) + } + return interceptor(ctx, in, info, handler) +} + +func _CertificateService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RepositoryCertificateCreateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CertificateServiceServer).Create(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/certificate.CertificateService/Create", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CertificateServiceServer).Create(ctx, req.(*RepositoryCertificateCreateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _CertificateService_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RepositoryCertificateQuery) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CertificateServiceServer).Delete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/certificate.CertificateService/Delete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CertificateServiceServer).Delete(ctx, req.(*RepositoryCertificateQuery)) + } + return interceptor(ctx, in, info, handler) +} + +var _CertificateService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "certificate.CertificateService", + HandlerType: (*CertificateServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "List", + Handler: _CertificateService_List_Handler, + }, + { + MethodName: "Create", + Handler: _CertificateService_Create_Handler, + }, + { + MethodName: "Delete", + Handler: _CertificateService_Delete_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "server/certificate/certificate.proto", +} + +func (m *RepositoryCertificateQuery) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RepositoryCertificateQuery) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.HostNamePattern) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintCertificate(dAtA, i, uint64(len(m.HostNamePattern))) + i += copy(dAtA[i:], m.HostNamePattern) + } + if len(m.CertType) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintCertificate(dAtA, i, uint64(len(m.CertType))) + i += copy(dAtA[i:], m.CertType) + } + if len(m.CertSubType) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintCertificate(dAtA, i, uint64(len(m.CertSubType))) + i += copy(dAtA[i:], m.CertSubType) + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *RepositoryCertificateCreateRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RepositoryCertificateCreateRequest) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.Certificates != nil { + dAtA[i] = 0xa + i++ + i = encodeVarintCertificate(dAtA, i, uint64(m.Certificates.Size())) + n1, err := m.Certificates.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n1 + } + if m.Upsert { + dAtA[i] = 0x10 + i++ + if m.Upsert { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func (m *RepositoryCertificateResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RepositoryCertificateResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + +func encodeVarintCertificate(dAtA []byte, offset int, v uint64) int { + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return offset + 1 +} +func (m *RepositoryCertificateQuery) Size() (n int) { + var l int + _ = l + l = len(m.HostNamePattern) + if l > 0 { + n += 1 + l + sovCertificate(uint64(l)) + } + l = len(m.CertType) + if l > 0 { + n += 1 + l + sovCertificate(uint64(l)) + } + l = len(m.CertSubType) + if l > 0 { + n += 1 + l + sovCertificate(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *RepositoryCertificateCreateRequest) Size() (n int) { + var l int + _ = l + if m.Certificates != nil { + l = m.Certificates.Size() + n += 1 + l + sovCertificate(uint64(l)) + } + if m.Upsert { + n += 2 + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *RepositoryCertificateResponse) Size() (n int) { + var l int + _ = l + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovCertificate(x uint64) (n int) { + for { + n++ + x >>= 7 + if x == 0 { + break + } + } + return n +} +func sozCertificate(x uint64) (n int) { + return sovCertificate(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *RepositoryCertificateQuery) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCertificate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RepositoryCertificateQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RepositoryCertificateQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostNamePattern", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCertificate + } + 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 ErrInvalidLengthCertificate + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostNamePattern = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CertType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCertificate + } + 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 ErrInvalidLengthCertificate + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CertType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CertSubType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCertificate + } + 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 ErrInvalidLengthCertificate + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CertSubType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCertificate(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCertificate + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RepositoryCertificateCreateRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCertificate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RepositoryCertificateCreateRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RepositoryCertificateCreateRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Certificates", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCertificate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCertificate + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Certificates == nil { + m.Certificates = &v1alpha1.RepositoryCertificateList{} + } + if err := m.Certificates.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Upsert", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCertificate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Upsert = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipCertificate(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCertificate + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RepositoryCertificateResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCertificate + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RepositoryCertificateResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RepositoryCertificateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipCertificate(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthCertificate + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipCertificate(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCertificate + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCertificate + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + return iNdEx, nil + case 1: + iNdEx += 8 + return iNdEx, nil + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCertificate + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + iNdEx += length + if length < 0 { + return 0, ErrInvalidLengthCertificate + } + return iNdEx, nil + case 3: + for { + var innerWire uint64 + var start int = iNdEx + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowCertificate + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + innerWire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + innerWireType := int(innerWire & 0x7) + if innerWireType == 4 { + break + } + next, err := skipCertificate(dAtA[start:]) + if err != nil { + return 0, err + } + iNdEx = start + next + } + return iNdEx, nil + case 4: + return iNdEx, nil + case 5: + iNdEx += 4 + return iNdEx, nil + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + } + panic("unreachable") +} + +var ( + ErrInvalidLengthCertificate = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowCertificate = fmt.Errorf("proto: integer overflow") +) + +func init() { + proto.RegisterFile("server/certificate/certificate.proto", fileDescriptor_certificate_7cceab803f50bba4) +} + +var fileDescriptor_certificate_7cceab803f50bba4 = []byte{ + // 448 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x53, 0x41, 0x6b, 0x14, 0x31, + 0x14, 0x26, 0xb5, 0x2c, 0x35, 0x15, 0x84, 0x50, 0x4a, 0x19, 0xea, 0x5a, 0x86, 0x82, 0xa5, 0x60, + 0xc2, 0x56, 0xbc, 0x78, 0x74, 0xbd, 0x08, 0x22, 0x3a, 0xed, 0xc9, 0x8b, 0x64, 0x67, 0x9f, 0xd9, + 0xd8, 0x69, 0x12, 0x93, 0x37, 0x83, 0x7b, 0x15, 0xff, 0x81, 0x7f, 0x40, 0x10, 0xff, 0x82, 0x17, + 0xff, 0x80, 0x47, 0xc1, 0x3f, 0x20, 0x8b, 0x3f, 0x44, 0x26, 0xdb, 0xda, 0x8c, 0x8c, 0xe8, 0x65, + 0xc1, 0xdb, 0xcb, 0xf7, 0x92, 0xf7, 0xbe, 0xef, 0x7b, 0x79, 0x74, 0x3f, 0x80, 0x6f, 0xc0, 0x8b, + 0x12, 0x3c, 0xea, 0x17, 0xba, 0x94, 0x08, 0x69, 0xcc, 0x9d, 0xb7, 0x68, 0xd9, 0x66, 0x02, 0x65, + 0x5b, 0xca, 0x2a, 0x1b, 0x71, 0xd1, 0x46, 0xcb, 0x2b, 0xd9, 0xae, 0xb2, 0x56, 0x55, 0x20, 0xa4, + 0xd3, 0x42, 0x1a, 0x63, 0x51, 0xa2, 0xb6, 0x26, 0x9c, 0x67, 0x1f, 0x2a, 0x8d, 0xb3, 0x7a, 0xc2, + 0x4b, 0x7b, 0x26, 0xa4, 0x8f, 0xcf, 0x5f, 0xc6, 0xe0, 0x76, 0x39, 0x15, 0xee, 0x54, 0xb5, 0xcf, + 0x82, 0x90, 0xce, 0x55, 0x6d, 0x0f, 0x6d, 0x8d, 0x68, 0x46, 0xb2, 0x72, 0x33, 0x39, 0x12, 0x0a, + 0x0c, 0x78, 0x89, 0x30, 0x5d, 0x96, 0xca, 0xdf, 0x12, 0x9a, 0x15, 0xe0, 0x6c, 0xd0, 0x68, 0xfd, + 0x7c, 0x7c, 0x49, 0xec, 0x69, 0x0d, 0x7e, 0xce, 0x0e, 0xe8, 0xf5, 0x99, 0x0d, 0xf8, 0x58, 0x9e, + 0xc1, 0x13, 0x89, 0x08, 0xde, 0xec, 0x90, 0x3d, 0x72, 0x70, 0xb5, 0xf8, 0x1d, 0x66, 0x19, 0xdd, + 0x68, 0x65, 0x9d, 0xcc, 0x1d, 0xec, 0xac, 0xc5, 0x2b, 0xbf, 0xce, 0x6c, 0x8f, 0x46, 0xc9, 0xc7, + 0xf5, 0x24, 0xa6, 0xaf, 0xc4, 0x74, 0x0a, 0xe5, 0x9f, 0x08, 0xcd, 0x7b, 0x69, 0x8c, 0x3d, 0x48, + 0x84, 0x02, 0x5e, 0xd5, 0x10, 0x90, 0xbd, 0xa6, 0xd7, 0x12, 0xef, 0x42, 0xe4, 0xb2, 0x79, 0x74, + 0xc2, 0x2f, 0xfd, 0xe0, 0x17, 0x7e, 0xc4, 0xe0, 0x79, 0x39, 0xe5, 0xee, 0x54, 0xf1, 0xd6, 0x0f, + 0x9e, 0xf8, 0xc1, 0x2f, 0xfc, 0xe0, 0xbd, 0x4d, 0x1f, 0xe9, 0x80, 0x45, 0xa7, 0x13, 0xdb, 0xa6, + 0x83, 0xda, 0x05, 0xf0, 0x18, 0xc5, 0x6d, 0x14, 0xe7, 0xa7, 0xfc, 0x26, 0xbd, 0xd1, 0x5b, 0xa2, + 0x80, 0xe0, 0xac, 0x09, 0x70, 0xf4, 0x7e, 0x9d, 0xb2, 0x04, 0x3f, 0x06, 0xdf, 0xe8, 0x12, 0xd8, + 0x07, 0x42, 0xd7, 0xdb, 0x36, 0xec, 0x16, 0x4f, 0x3f, 0xc8, 0x9f, 0x47, 0x91, 0xad, 0x44, 0x65, + 0xbe, 0xfb, 0xe6, 0xdb, 0x8f, 0x77, 0x6b, 0xdb, 0x6c, 0x2b, 0x7e, 0xb5, 0x66, 0x24, 0x3a, 0xaa, + 0x3f, 0x13, 0x3a, 0x58, 0x4e, 0x80, 0x89, 0xbf, 0xf3, 0xec, 0xcc, 0x6a, 0x45, 0x7c, 0x0f, 0x23, + 0xdf, 0xfd, 0xbc, 0x97, 0xef, 0xbd, 0xee, 0xcc, 0x3e, 0x12, 0x3a, 0x78, 0x00, 0x15, 0x20, 0xfc, + 0x27, 0x2e, 0x1f, 0xf6, 0xb2, 0xbe, 0x3f, 0xfe, 0xb2, 0x18, 0x92, 0xaf, 0x8b, 0x21, 0xf9, 0xbe, + 0x18, 0x92, 0x67, 0x77, 0xff, 0x61, 0xb9, 0xcb, 0x4a, 0x83, 0xc1, 0xb4, 0xca, 0x64, 0x10, 0xf7, + 0xf9, 0xce, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x07, 0xb9, 0x98, 0x4b, 0x83, 0x04, 0x00, 0x00, +} diff --git a/pkg/apiclient/certificate/certificate.pb.gw.go b/pkg/apiclient/certificate/certificate.pb.gw.go new file mode 100644 index 0000000000000..50e46becf8986 --- /dev/null +++ b/pkg/apiclient/certificate/certificate.pb.gw.go @@ -0,0 +1,228 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: server/certificate/certificate.proto + +/* +Package certificate is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package certificate + +import ( + "io" + "net/http" + + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/status" +) + +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray + +var ( + filter_CertificateService_List_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_CertificateService_List_0(ctx context.Context, marshaler runtime.Marshaler, client CertificateServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RepositoryCertificateQuery + var metadata runtime.ServerMetadata + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_CertificateService_List_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.List(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +var ( + filter_CertificateService_Create_0 = &utilities.DoubleArray{Encoding: map[string]int{"certificates": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + +func request_CertificateService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client CertificateServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RepositoryCertificateCreateRequest + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Certificates); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_CertificateService_Create_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Create(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +var ( + filter_CertificateService_Delete_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_CertificateService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client CertificateServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RepositoryCertificateQuery + var metadata runtime.ServerMetadata + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_CertificateService_Delete_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.Delete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +// RegisterCertificateServiceHandlerFromEndpoint is same as RegisterCertificateServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterCertificateServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterCertificateServiceHandler(ctx, mux, conn) +} + +// RegisterCertificateServiceHandler registers the http handlers for service CertificateService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterCertificateServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterCertificateServiceHandlerClient(ctx, mux, NewCertificateServiceClient(conn)) +} + +// RegisterCertificateServiceHandler registers the http handlers for service CertificateService to "mux". +// The handlers forward requests to the grpc endpoint over the given implementation of "CertificateServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "CertificateServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "CertificateServiceClient" to call the correct interceptors. +func RegisterCertificateServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client CertificateServiceClient) error { + + mux.Handle("GET", pattern_CertificateService_List_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_CertificateService_List_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_CertificateService_List_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_CertificateService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_CertificateService_Create_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_CertificateService_Create_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_CertificateService_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_CertificateService_Delete_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_CertificateService_Delete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_CertificateService_List_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "certificates"}, "")) + + pattern_CertificateService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "certificates"}, "")) + + pattern_CertificateService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "certificates"}, "")) +) + +var ( + forward_CertificateService_List_0 = runtime.ForwardResponseMessage + + forward_CertificateService_Create_0 = runtime.ForwardResponseMessage + + forward_CertificateService_Delete_0 = runtime.ForwardResponseMessage +) diff --git a/pkg/apiclient/repository/repository.pb.go b/pkg/apiclient/repository/repository.pb.go index c755d0a743ec8..ebcdd9d05d45b 100644 --- a/pkg/apiclient/repository/repository.pb.go +++ b/pkg/apiclient/repository/repository.pb.go @@ -47,7 +47,7 @@ func (m *RepoAppsQuery) Reset() { *m = RepoAppsQuery{} } func (m *RepoAppsQuery) String() string { return proto.CompactTextString(m) } func (*RepoAppsQuery) ProtoMessage() {} func (*RepoAppsQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_repository_085a58cd976bcc45, []int{0} + return fileDescriptor_repository_fd679778f6b4cef4, []int{0} } func (m *RepoAppsQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -103,7 +103,7 @@ func (m *AppInfo) Reset() { *m = AppInfo{} } func (m *AppInfo) String() string { return proto.CompactTextString(m) } func (*AppInfo) ProtoMessage() {} func (*AppInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_repository_085a58cd976bcc45, []int{1} + return fileDescriptor_repository_fd679778f6b4cef4, []int{1} } func (m *AppInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -162,7 +162,7 @@ func (m *RepoAppDetailsQuery) Reset() { *m = RepoAppDetailsQuery{} } func (m *RepoAppDetailsQuery) String() string { return proto.CompactTextString(m) } func (*RepoAppDetailsQuery) ProtoMessage() {} func (*RepoAppDetailsQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_repository_085a58cd976bcc45, []int{2} + return fileDescriptor_repository_fd679778f6b4cef4, []int{2} } func (m *RepoAppDetailsQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -238,7 +238,7 @@ func (m *RepoAppsResponse) Reset() { *m = RepoAppsResponse{} } func (m *RepoAppsResponse) String() string { return proto.CompactTextString(m) } func (*RepoAppsResponse) ProtoMessage() {} func (*RepoAppsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_repository_085a58cd976bcc45, []int{3} + return fileDescriptor_repository_fd679778f6b4cef4, []int{3} } func (m *RepoAppsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -286,7 +286,7 @@ func (m *RepoQuery) Reset() { *m = RepoQuery{} } func (m *RepoQuery) String() string { return proto.CompactTextString(m) } func (*RepoQuery) ProtoMessage() {} func (*RepoQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_repository_085a58cd976bcc45, []int{4} + return fileDescriptor_repository_fd679778f6b4cef4, []int{4} } func (m *RepoQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -322,6 +322,91 @@ func (m *RepoQuery) GetRepo() string { return "" } +// RepoAccessQuery is a query for checking access to a repo +type RepoAccessQuery struct { + // The URL to the repo + Repo string `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"` + // Username for accessing repo + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + // Password for accessing repo + Password string `protobuf:"bytes,3,opt,name=password,proto3" json:"password,omitempty"` + // Private key data for accessing SSH repository + SshPrivateKey string `protobuf:"bytes,4,opt,name=sshPrivateKey,proto3" json:"sshPrivateKey,omitempty"` + // Whether to skip certificate or host key validation + Insecure bool `protobuf:"varint,5,opt,name=insecure,proto3" json:"insecure,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RepoAccessQuery) Reset() { *m = RepoAccessQuery{} } +func (m *RepoAccessQuery) String() string { return proto.CompactTextString(m) } +func (*RepoAccessQuery) ProtoMessage() {} +func (*RepoAccessQuery) Descriptor() ([]byte, []int) { + return fileDescriptor_repository_fd679778f6b4cef4, []int{5} +} +func (m *RepoAccessQuery) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RepoAccessQuery) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RepoAccessQuery.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (dst *RepoAccessQuery) XXX_Merge(src proto.Message) { + xxx_messageInfo_RepoAccessQuery.Merge(dst, src) +} +func (m *RepoAccessQuery) XXX_Size() int { + return m.Size() +} +func (m *RepoAccessQuery) XXX_DiscardUnknown() { + xxx_messageInfo_RepoAccessQuery.DiscardUnknown(m) +} + +var xxx_messageInfo_RepoAccessQuery proto.InternalMessageInfo + +func (m *RepoAccessQuery) GetRepo() string { + if m != nil { + return m.Repo + } + return "" +} + +func (m *RepoAccessQuery) GetUsername() string { + if m != nil { + return m.Username + } + return "" +} + +func (m *RepoAccessQuery) GetPassword() string { + if m != nil { + return m.Password + } + return "" +} + +func (m *RepoAccessQuery) GetSshPrivateKey() string { + if m != nil { + return m.SshPrivateKey + } + return "" +} + +func (m *RepoAccessQuery) GetInsecure() bool { + if m != nil { + return m.Insecure + } + return false +} + type RepoResponse struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -332,7 +417,7 @@ func (m *RepoResponse) Reset() { *m = RepoResponse{} } func (m *RepoResponse) String() string { return proto.CompactTextString(m) } func (*RepoResponse) ProtoMessage() {} func (*RepoResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_repository_085a58cd976bcc45, []int{5} + return fileDescriptor_repository_fd679778f6b4cef4, []int{6} } func (m *RepoResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -373,7 +458,7 @@ func (m *RepoCreateRequest) Reset() { *m = RepoCreateRequest{} } func (m *RepoCreateRequest) String() string { return proto.CompactTextString(m) } func (*RepoCreateRequest) ProtoMessage() {} func (*RepoCreateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_repository_085a58cd976bcc45, []int{6} + return fileDescriptor_repository_fd679778f6b4cef4, []int{7} } func (m *RepoCreateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -427,7 +512,7 @@ func (m *RepoUpdateRequest) Reset() { *m = RepoUpdateRequest{} } func (m *RepoUpdateRequest) String() string { return proto.CompactTextString(m) } func (*RepoUpdateRequest) ProtoMessage() {} func (*RepoUpdateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_repository_085a58cd976bcc45, []int{7} + return fileDescriptor_repository_fd679778f6b4cef4, []int{8} } func (m *RepoUpdateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -469,6 +554,7 @@ func init() { proto.RegisterType((*RepoAppDetailsQuery)(nil), "repository.RepoAppDetailsQuery") proto.RegisterType((*RepoAppsResponse)(nil), "repository.RepoAppsResponse") proto.RegisterType((*RepoQuery)(nil), "repository.RepoQuery") + proto.RegisterType((*RepoAccessQuery)(nil), "repository.RepoAccessQuery") proto.RegisterType((*RepoResponse)(nil), "repository.RepoResponse") proto.RegisterType((*RepoCreateRequest)(nil), "repository.RepoCreateRequest") proto.RegisterType((*RepoUpdateRequest)(nil), "repository.RepoUpdateRequest") @@ -497,6 +583,8 @@ type RepositoryServiceClient interface { Update(ctx context.Context, in *RepoUpdateRequest, opts ...grpc.CallOption) (*v1alpha1.Repository, error) // Delete deletes a repo Delete(ctx context.Context, in *RepoQuery, opts ...grpc.CallOption) (*RepoResponse, error) + // ValidateAccess validates access to a repository with given parameters + ValidateAccess(ctx context.Context, in *RepoAccessQuery, opts ...grpc.CallOption) (*RepoResponse, error) } type repositoryServiceClient struct { @@ -561,6 +649,15 @@ func (c *repositoryServiceClient) Delete(ctx context.Context, in *RepoQuery, opt return out, nil } +func (c *repositoryServiceClient) ValidateAccess(ctx context.Context, in *RepoAccessQuery, opts ...grpc.CallOption) (*RepoResponse, error) { + out := new(RepoResponse) + err := c.cc.Invoke(ctx, "/repository.RepositoryService/ValidateAccess", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // Server API for RepositoryService service type RepositoryServiceServer interface { @@ -576,6 +673,8 @@ type RepositoryServiceServer interface { Update(context.Context, *RepoUpdateRequest) (*v1alpha1.Repository, error) // Delete deletes a repo Delete(context.Context, *RepoQuery) (*RepoResponse, error) + // ValidateAccess validates access to a repository with given parameters + ValidateAccess(context.Context, *RepoAccessQuery) (*RepoResponse, error) } func RegisterRepositoryServiceServer(s *grpc.Server, srv RepositoryServiceServer) { @@ -690,6 +789,24 @@ func _RepositoryService_Delete_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _RepositoryService_ValidateAccess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RepoAccessQuery) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RepositoryServiceServer).ValidateAccess(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/repository.RepositoryService/ValidateAccess", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RepositoryServiceServer).ValidateAccess(ctx, req.(*RepoAccessQuery)) + } + return interceptor(ctx, in, info, handler) +} + var _RepositoryService_serviceDesc = grpc.ServiceDesc{ ServiceName: "repository.RepositoryService", HandlerType: (*RepositoryServiceServer)(nil), @@ -718,6 +835,10 @@ var _RepositoryService_serviceDesc = grpc.ServiceDesc{ MethodName: "Delete", Handler: _RepositoryService_Delete_Handler, }, + { + MethodName: "ValidateAccess", + Handler: _RepositoryService_ValidateAccess_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "server/repository/repository.proto", @@ -908,6 +1029,61 @@ func (m *RepoQuery) MarshalTo(dAtA []byte) (int, error) { return i, nil } +func (m *RepoAccessQuery) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RepoAccessQuery) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Repo) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintRepository(dAtA, i, uint64(len(m.Repo))) + i += copy(dAtA[i:], m.Repo) + } + if len(m.Username) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintRepository(dAtA, i, uint64(len(m.Username))) + i += copy(dAtA[i:], m.Username) + } + if len(m.Password) > 0 { + dAtA[i] = 0x1a + i++ + i = encodeVarintRepository(dAtA, i, uint64(len(m.Password))) + i += copy(dAtA[i:], m.Password) + } + if len(m.SshPrivateKey) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintRepository(dAtA, i, uint64(len(m.SshPrivateKey))) + i += copy(dAtA[i:], m.SshPrivateKey) + } + if m.Insecure { + dAtA[i] = 0x28 + i++ + if m.Insecure { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ + } + if m.XXX_unrecognized != nil { + i += copy(dAtA[i:], m.XXX_unrecognized) + } + return i, nil +} + func (m *RepoResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1101,6 +1277,34 @@ func (m *RepoQuery) Size() (n int) { return n } +func (m *RepoAccessQuery) Size() (n int) { + var l int + _ = l + l = len(m.Repo) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Username) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Password) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.SshPrivateKey) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.Insecure { + n += 2 + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *RepoResponse) Size() (n int) { var l int _ = l @@ -1736,6 +1940,193 @@ func (m *RepoQuery) Unmarshal(dAtA []byte) error { } return nil } +func (m *RepoAccessQuery) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RepoAccessQuery: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RepoAccessQuery: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Repo", 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 > l { + return io.ErrUnexpectedEOF + } + m.Repo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Username", 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 > l { + return io.ErrUnexpectedEOF + } + m.Username = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Password", 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 > l { + return io.ErrUnexpectedEOF + } + m.Password = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SshPrivateKey", 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 > l { + return io.ErrUnexpectedEOF + } + m.SshPrivateKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Insecure", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Insecure = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *RepoResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -2081,52 +2472,58 @@ var ( ) func init() { - proto.RegisterFile("server/repository/repository.proto", fileDescriptor_repository_085a58cd976bcc45) -} - -var fileDescriptor_repository_085a58cd976bcc45 = []byte{ - // 679 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0xc1, 0x6e, 0x13, 0x3d, - 0x10, 0xd6, 0xb6, 0x69, 0xda, 0xba, 0x7f, 0x7f, 0x81, 0x5b, 0xaa, 0xb0, 0xa4, 0x6d, 0x64, 0x0e, - 0xa4, 0x48, 0xac, 0x95, 0x94, 0x03, 0x42, 0x20, 0xd4, 0x52, 0x04, 0x15, 0x5c, 0x58, 0xc4, 0x01, - 0x0e, 0xa0, 0xed, 0x66, 0xd8, 0x98, 0x6c, 0xd6, 0xc6, 0x76, 0x22, 0x55, 0x55, 0x2f, 0x48, 0xf4, - 0x01, 0xe0, 0xce, 0x9d, 0x37, 0xe1, 0xc0, 0x01, 0x89, 0x17, 0x40, 0x15, 0x0f, 0x82, 0xec, 0xdd, - 0x6c, 0xb6, 0x69, 0xda, 0x22, 0x54, 0x71, 0x9b, 0x1d, 0xcf, 0x37, 0xdf, 0x67, 0xcf, 0xe7, 0x35, - 0x22, 0x0a, 0x64, 0x1f, 0x24, 0x95, 0x20, 0xb8, 0x62, 0x9a, 0xcb, 0xdd, 0x42, 0xe8, 0x09, 0xc9, - 0x35, 0xc7, 0x68, 0x98, 0x71, 0x17, 0x23, 0x1e, 0x71, 0x9b, 0xa6, 0x26, 0x4a, 0x2b, 0xdc, 0x6a, - 0xc4, 0x79, 0x14, 0x03, 0x0d, 0x04, 0xa3, 0x41, 0x92, 0x70, 0x1d, 0x68, 0xc6, 0x13, 0x95, 0xad, - 0x92, 0xce, 0x2d, 0xe5, 0x31, 0x6e, 0x57, 0x43, 0x2e, 0x81, 0xf6, 0x1b, 0x34, 0x82, 0x04, 0x64, - 0xa0, 0xa1, 0x95, 0xd5, 0x6c, 0x47, 0x4c, 0xb7, 0x7b, 0x3b, 0x5e, 0xc8, 0xbb, 0x34, 0x90, 0x96, - 0xe2, 0xad, 0x0d, 0x6e, 0x84, 0x2d, 0x2a, 0x3a, 0x91, 0x01, 0x2b, 0x1a, 0x08, 0x11, 0xb3, 0xd0, - 0x36, 0xa7, 0xfd, 0x46, 0x10, 0x8b, 0x76, 0x70, 0xbc, 0xd5, 0xe6, 0x69, 0xad, 0xec, 0x56, 0xce, - 0xdc, 0x32, 0xb9, 0x87, 0xe6, 0x7d, 0x10, 0x7c, 0x43, 0x08, 0xf5, 0xb4, 0x07, 0x72, 0x17, 0x63, - 0x54, 0x32, 0x45, 0x15, 0xa7, 0xe6, 0xd4, 0x67, 0x7d, 0x1b, 0x63, 0x17, 0xcd, 0x48, 0xe8, 0x33, - 0xc5, 0x78, 0x52, 0x99, 0xb0, 0xf9, 0xfc, 0x9b, 0x34, 0xd0, 0xf4, 0x86, 0x10, 0xdb, 0xc9, 0x1b, - 0x6e, 0xa0, 0x7a, 0x57, 0xc0, 0x00, 0x6a, 0x62, 0x93, 0x13, 0x81, 0x6e, 0x67, 0x30, 0x1b, 0x93, - 0x6f, 0x0e, 0x5a, 0xc8, 0x48, 0xb7, 0x40, 0x07, 0x2c, 0xfe, 0x3b, 0xea, 0xbc, 0xf7, 0xe4, 0xb0, - 0x37, 0x5e, 0x47, 0xa5, 0x36, 0xc4, 0xdd, 0x4a, 0xa9, 0xe6, 0xd4, 0xe7, 0x9a, 0xab, 0x5e, 0x61, - 0xc3, 0x8f, 0x20, 0xee, 0x8e, 0x50, 0xfa, 0xb6, 0x18, 0xdf, 0x41, 0xd3, 0x1d, 0xc5, 0x93, 0x04, - 0x74, 0x65, 0xca, 0xe2, 0x48, 0x11, 0xf7, 0x38, 0x5d, 0x1a, 0x85, 0x0e, 0x20, 0xe4, 0x2e, 0xba, - 0x30, 0x38, 0x42, 0x1f, 0x94, 0xe0, 0x89, 0x02, 0xbc, 0x86, 0xa6, 0x98, 0x86, 0xae, 0xaa, 0x38, - 0xb5, 0xc9, 0xfa, 0x5c, 0x73, 0xa1, 0xd8, 0x2f, 0x3b, 0x2e, 0x3f, 0xad, 0x20, 0xab, 0x68, 0xd6, - 0xc0, 0x4f, 0x3c, 0x02, 0xf2, 0x3f, 0xfa, 0xcf, 0x14, 0x0c, 0x7a, 0x93, 0x03, 0x07, 0x5d, 0x34, - 0x89, 0xfb, 0x12, 0x02, 0x0d, 0x3e, 0xbc, 0xeb, 0x81, 0xd2, 0xf8, 0x45, 0x01, 0x39, 0xd7, 0x7c, - 0xe0, 0x0d, 0xbd, 0xe1, 0x0d, 0xbc, 0x61, 0x83, 0xd7, 0x61, 0xcb, 0x13, 0x9d, 0xc8, 0x33, 0x36, - 0xf3, 0x0a, 0x36, 0xf3, 0x06, 0x36, 0xf3, 0xfc, 0x5c, 0x6a, 0x36, 0x83, 0x25, 0x54, 0xee, 0x09, - 0x05, 0x52, 0xdb, 0x09, 0xcc, 0xf8, 0xd9, 0x17, 0x49, 0x52, 0x1d, 0xcf, 0x45, 0xeb, 0x9f, 0xe8, - 0x68, 0x7e, 0x29, 0xa7, 0x84, 0x69, 0xf2, 0x19, 0xc8, 0x3e, 0x0b, 0x01, 0x1f, 0x38, 0xa8, 0xf4, - 0x84, 0x29, 0x8d, 0x2f, 0x15, 0x0f, 0x39, 0x3f, 0x52, 0x77, 0xfb, 0x5c, 0x24, 0x18, 0x06, 0x52, - 0x7d, 0xff, 0xe3, 0xd7, 0xa7, 0x89, 0x25, 0xbc, 0x68, 0x6f, 0x78, 0xbf, 0x31, 0xbc, 0x4e, 0x0c, - 0x14, 0xee, 0xa2, 0x19, 0x53, 0x65, 0x7c, 0x80, 0x2f, 0x8f, 0x6a, 0xc9, 0x2f, 0x98, 0x5b, 0x1d, - 0xb7, 0x94, 0x0f, 0xb7, 0x6e, 0x29, 0x08, 0xae, 0x8d, 0xa3, 0xa0, 0x7b, 0xe6, 0x6b, 0xdf, 0xfc, - 0x1d, 0x14, 0xfe, 0xe0, 0xa0, 0xf9, 0x87, 0x45, 0x5b, 0xe2, 0xd5, 0x31, 0x9d, 0x8b, 0x96, 0x75, - 0xc9, 0xc9, 0x05, 0xb9, 0x00, 0x6a, 0x05, 0xac, 0xe1, 0x6b, 0x67, 0x09, 0xa0, 0x7b, 0xe6, 0xc2, - 0xed, 0xe3, 0x8f, 0x0e, 0x2a, 0xa7, 0x56, 0xc4, 0xcb, 0xa3, 0xfd, 0x8f, 0x58, 0xd4, 0x3d, 0x1f, - 0x33, 0x10, 0x62, 0x15, 0x56, 0xc9, 0xd8, 0x29, 0xdc, 0x4e, 0x2d, 0xfb, 0xd9, 0x41, 0xe5, 0xd4, - 0x97, 0xc7, 0x45, 0x1d, 0xf1, 0xeb, 0x79, 0x89, 0xf2, 0xac, 0xa8, 0xba, 0x7b, 0xca, 0xdc, 0xac, - 0x8e, 0xfd, 0x4c, 0xe0, 0x2b, 0x54, 0xde, 0x82, 0x18, 0x34, 0x9c, 0x64, 0xdb, 0xca, 0x68, 0x3a, - 0x9f, 0xd0, 0x55, 0x4b, 0xb5, 0x7c, 0xfd, 0xca, 0x29, 0x13, 0xda, 0xdc, 0xfc, 0x7a, 0xb8, 0xe2, - 0x7c, 0x3f, 0x5c, 0x71, 0x7e, 0x1e, 0xae, 0x38, 0x2f, 0x6f, 0xfe, 0xc1, 0xa3, 0x13, 0xc6, 0x0c, - 0x12, 0x5d, 0x78, 0x21, 0x76, 0xca, 0xf6, 0x89, 0x58, 0xff, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x24, - 0xdc, 0xe6, 0x9b, 0x3b, 0x07, 0x00, 0x00, + proto.RegisterFile("server/repository/repository.proto", fileDescriptor_repository_fd679778f6b4cef4) +} + +var fileDescriptor_repository_fd679778f6b4cef4 = []byte{ + // 784 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xd7, 0x26, 0x8e, 0xe3, 0x4c, 0x48, 0x80, 0x49, 0x88, 0xcc, 0xc6, 0x49, 0xac, 0x21, 0x12, + 0x0e, 0x82, 0x5d, 0xd9, 0xe1, 0x80, 0x10, 0x08, 0x25, 0x04, 0x41, 0x14, 0x0e, 0xb0, 0x08, 0x24, + 0x38, 0x80, 0x36, 0xeb, 0xc7, 0x7a, 0xf0, 0x7a, 0x67, 0x98, 0x19, 0x2f, 0xb2, 0xa2, 0x5c, 0x90, + 0x9a, 0x0f, 0xd0, 0xde, 0xdb, 0x5b, 0x3f, 0x4b, 0x0f, 0x3d, 0x54, 0xea, 0x17, 0xa8, 0xa2, 0x7e, + 0x90, 0x6a, 0x66, 0xff, 0x78, 0xe3, 0x38, 0x4e, 0x55, 0x45, 0xbd, 0xbd, 0x79, 0xf3, 0xde, 0xfb, + 0xfd, 0xde, 0x9f, 0x79, 0x83, 0x88, 0x04, 0x91, 0x80, 0x70, 0x05, 0x70, 0x26, 0xa9, 0x62, 0x62, + 0x54, 0x12, 0x1d, 0x2e, 0x98, 0x62, 0x18, 0x8d, 0x35, 0xf6, 0x7a, 0xc8, 0x42, 0x66, 0xd4, 0xae, + 0x96, 0x52, 0x0b, 0xbb, 0x11, 0x32, 0x16, 0x46, 0xe0, 0xfa, 0x9c, 0xba, 0x7e, 0x1c, 0x33, 0xe5, + 0x2b, 0xca, 0x62, 0x99, 0xdd, 0x92, 0xfe, 0x17, 0xd2, 0xa1, 0xcc, 0xdc, 0x06, 0x4c, 0x80, 0x9b, + 0xb4, 0xdd, 0x10, 0x62, 0x10, 0xbe, 0x82, 0x6e, 0x66, 0x73, 0x1c, 0x52, 0xd5, 0x1b, 0x9e, 0x3a, + 0x01, 0x1b, 0xb8, 0xbe, 0x30, 0x10, 0xff, 0x18, 0xe1, 0xb3, 0xa0, 0xeb, 0xf2, 0x7e, 0xa8, 0x9d, + 0xa5, 0xeb, 0x73, 0x1e, 0xd1, 0xc0, 0x04, 0x77, 0x93, 0xb6, 0x1f, 0xf1, 0x9e, 0x7f, 0x3d, 0xd4, + 0xe1, 0xac, 0x50, 0x26, 0x95, 0x5b, 0x53, 0x26, 0xdf, 0xa0, 0x15, 0x0f, 0x38, 0x3b, 0xe0, 0x5c, + 0xfe, 0x3c, 0x04, 0x31, 0xc2, 0x18, 0x55, 0xb4, 0x51, 0xdd, 0x6a, 0x5a, 0xad, 0x25, 0xcf, 0xc8, + 0xd8, 0x46, 0x35, 0x01, 0x09, 0x95, 0x94, 0xc5, 0xf5, 0x39, 0xa3, 0x2f, 0xce, 0xa4, 0x8d, 0x16, + 0x0f, 0x38, 0x3f, 0x8e, 0xff, 0x66, 0xda, 0x55, 0x8d, 0x38, 0xe4, 0xae, 0x5a, 0xd6, 0x3a, 0xee, + 0xab, 0x5e, 0xe6, 0x66, 0x64, 0xf2, 0xd4, 0x42, 0x6b, 0x19, 0xe8, 0x11, 0x28, 0x9f, 0x46, 0x6f, + 0x06, 0x5d, 0xc4, 0x9e, 0x1f, 0xc7, 0xc6, 0xfb, 0xa8, 0xd2, 0x83, 0x68, 0x50, 0xaf, 0x34, 0xad, + 0xd6, 0x72, 0x67, 0xc7, 0x29, 0x25, 0xfc, 0x03, 0x44, 0x83, 0x09, 0x48, 0xcf, 0x18, 0xe3, 0xaf, + 0xd0, 0x62, 0x5f, 0xb2, 0x38, 0x06, 0x55, 0x5f, 0x30, 0x7e, 0xa4, 0xec, 0x77, 0x92, 0x5e, 0x4d, + 0xba, 0xe6, 0x2e, 0xe4, 0x6b, 0xf4, 0x5e, 0x5e, 0x42, 0x0f, 0x24, 0x67, 0xb1, 0x04, 0xbc, 0x87, + 0x16, 0xa8, 0x82, 0x81, 0xac, 0x5b, 0xcd, 0xf9, 0xd6, 0x72, 0x67, 0xad, 0x1c, 0x2f, 0x2b, 0x97, + 0x97, 0x5a, 0x90, 0x1d, 0xb4, 0xa4, 0xdd, 0x6f, 0x2c, 0x01, 0x79, 0x64, 0xa1, 0x77, 0x0d, 0x40, + 0x10, 0x80, 0x9c, 0x5d, 0xaa, 0xa1, 0x04, 0x11, 0xfb, 0x03, 0xc8, 0x4b, 0x95, 0x9f, 0xf5, 0x1d, + 0xf7, 0xa5, 0xfc, 0x8f, 0x89, 0x6e, 0x56, 0xae, 0xe2, 0x8c, 0x77, 0xd1, 0x8a, 0x94, 0xbd, 0x9f, + 0x04, 0x4d, 0x7c, 0x05, 0x27, 0x30, 0x32, 0xb5, 0x5b, 0xf2, 0xae, 0x2a, 0x75, 0x04, 0x1a, 0x4b, + 0x08, 0x86, 0x02, 0x4c, 0x91, 0x6a, 0x5e, 0x71, 0x26, 0xab, 0xe8, 0x1d, 0x4d, 0x30, 0xcf, 0x9e, + 0x5c, 0x58, 0xe8, 0x7d, 0xad, 0xf8, 0x56, 0x80, 0xaf, 0xc0, 0x83, 0x7f, 0x87, 0x20, 0x15, 0xfe, + 0xbd, 0xc4, 0x79, 0xb9, 0xf3, 0x9d, 0x33, 0x9e, 0x5e, 0x27, 0x9f, 0x5e, 0x23, 0xfc, 0x15, 0x74, + 0x1d, 0xde, 0x0f, 0x1d, 0xfd, 0x10, 0x9c, 0xd2, 0x43, 0x70, 0xf2, 0x87, 0xe0, 0x78, 0x45, 0x31, + 0xb3, 0xd4, 0x37, 0x50, 0x75, 0xc8, 0x25, 0x08, 0x65, 0x12, 0xaf, 0x79, 0xd9, 0x89, 0xc4, 0x29, + 0x8f, 0x5f, 0x79, 0xf7, 0xad, 0xf0, 0xe8, 0x3c, 0x5e, 0x4c, 0x01, 0x53, 0xe5, 0x2f, 0x20, 0x12, + 0x1a, 0x00, 0xbe, 0xb0, 0x50, 0xe5, 0x47, 0x2a, 0x15, 0xfe, 0xa0, 0x3c, 0x06, 0x45, 0xd3, 0xed, + 0xe3, 0x3b, 0xa1, 0xa0, 0x11, 0x48, 0xe3, 0xff, 0xe7, 0x2f, 0x1f, 0xcc, 0x6d, 0xe0, 0x75, 0xb3, + 0x83, 0x92, 0xf6, 0xf8, 0xc1, 0x53, 0x90, 0x78, 0x80, 0x6a, 0xda, 0x4a, 0x4f, 0x2a, 0xfe, 0x70, + 0x92, 0x4b, 0xb1, 0x02, 0xec, 0xc6, 0xb4, 0xab, 0xa2, 0xb9, 0x2d, 0x03, 0x41, 0x70, 0x73, 0x1a, + 0x84, 0x7b, 0xa6, 0x4f, 0xe7, 0x7a, 0x7f, 0x49, 0x7c, 0xcf, 0x42, 0x2b, 0xdf, 0x97, 0x1f, 0x0e, + 0xde, 0x99, 0x12, 0xb9, 0xfc, 0xa8, 0x6c, 0x72, 0xb3, 0x41, 0x41, 0xc0, 0x35, 0x04, 0xf6, 0xf0, + 0xc7, 0xb7, 0x11, 0x70, 0xcf, 0xf4, 0x4a, 0x38, 0xc7, 0xf7, 0x2d, 0x54, 0x4d, 0x47, 0x11, 0x6f, + 0x4d, 0xc6, 0xbf, 0x32, 0xa2, 0xf6, 0xdd, 0x0c, 0x03, 0x21, 0x86, 0x61, 0x83, 0x4c, 0xed, 0xc2, + 0x97, 0xe9, 0xc8, 0x3e, 0xb4, 0x50, 0x35, 0x9d, 0xcb, 0xeb, 0xa4, 0xae, 0xcc, 0xeb, 0x5d, 0x91, + 0x72, 0x0c, 0xa9, 0x96, 0x3d, 0xa3, 0x6f, 0x86, 0xc7, 0x79, 0x46, 0xf0, 0x4f, 0x54, 0x3d, 0x82, + 0x08, 0x14, 0xdc, 0x34, 0xb6, 0xf5, 0x49, 0x75, 0xd1, 0xa1, 0x8f, 0x0c, 0xd4, 0xd6, 0x27, 0x9b, + 0x33, 0x3a, 0x84, 0xcf, 0xd0, 0xea, 0x6f, 0x7e, 0x44, 0x75, 0xa6, 0xe9, 0x66, 0xc3, 0x9b, 0xd7, + 0x9a, 0x3f, 0xde, 0x78, 0x33, 0xd0, 0x3a, 0x06, 0xed, 0x53, 0xb2, 0x3b, 0x6b, 0x1e, 0x92, 0x0c, + 0x2a, 0x4d, 0xee, 0xf0, 0xf0, 0xc9, 0xe5, 0xb6, 0xf5, 0xec, 0x72, 0xdb, 0x7a, 0x71, 0xb9, 0x6d, + 0xfd, 0xf1, 0xf9, 0x6b, 0xfc, 0xc9, 0x41, 0x44, 0x21, 0x56, 0xa5, 0x0f, 0xf4, 0xb4, 0x6a, 0x7e, + 0xd0, 0xfd, 0x57, 0x01, 0x00, 0x00, 0xff, 0xff, 0x44, 0x05, 0xf6, 0xec, 0x5a, 0x08, 0x00, 0x00, } diff --git a/pkg/apiclient/repository/repository.pb.gw.go b/pkg/apiclient/repository/repository.pb.gw.go index 5c59397e441c6..a94374b67e296 100644 --- a/pkg/apiclient/repository/repository.pb.gw.go +++ b/pkg/apiclient/repository/repository.pb.gw.go @@ -205,6 +205,45 @@ func request_RepositoryService_Delete_0(ctx context.Context, marshaler runtime.M } +var ( + filter_RepositoryService_ValidateAccess_0 = &utilities.DoubleArray{Encoding: map[string]int{"repo": 0}, Base: []int{1, 2, 0, 0}, Check: []int{0, 1, 2, 2}} +) + +func request_RepositoryService_ValidateAccess_0(ctx context.Context, marshaler runtime.Marshaler, client RepositoryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RepoAccessQuery + var metadata runtime.ServerMetadata + + if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Repo); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["repo"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "repo") + } + + protoReq.Repo, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "repo", err) + } + + if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_RepositoryService_ValidateAccess_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ValidateAccess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + // RegisterRepositoryServiceHandlerFromEndpoint is same as RegisterRepositoryServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterRepositoryServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { @@ -417,6 +456,35 @@ func RegisterRepositoryServiceHandlerClient(ctx context.Context, mux *runtime.Se }) + mux.Handle("POST", pattern_RepositoryService_ValidateAccess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + if cn, ok := w.(http.CloseNotifier); ok { + go func(done <-chan struct{}, closed <-chan bool) { + select { + case <-done: + case <-closed: + cancel() + } + }(ctx.Done(), cn.CloseNotify()) + } + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_RepositoryService_ValidateAccess_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_RepositoryService_ValidateAccess_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -432,6 +500,8 @@ var ( pattern_RepositoryService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "repositories", "repo.repo"}, "")) pattern_RepositoryService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "repositories", "repo"}, "")) + + pattern_RepositoryService_ValidateAccess_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "repositories", "repo", "validate"}, "")) ) var ( @@ -446,4 +516,6 @@ var ( forward_RepositoryService_Update_0 = runtime.ForwardResponseMessage forward_RepositoryService_Delete_0 = runtime.ForwardResponseMessage + + forward_RepositoryService_ValidateAccess_0 = runtime.ForwardResponseMessage ) diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index 7ab877939810b..625f160a0b857 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -2,6 +2,11 @@ API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,ConnectionState,ModifiedAt API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,JWTToken,ExpiresAt API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,JWTToken,IssuedAt +API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,RepositoryCertificate,CertData +API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,RepositoryCertificate,CertFingerprint +API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,RepositoryCertificate,CertSubType +API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,RepositoryCertificate,CertType +API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,RepositoryCertificate,ServerName API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,ResourceActionDefinition,ActionLua API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,ResourceActions,ActionDiscoveryLua API rule violation: names_match,github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1,ResourceOverride,HealthLua diff --git a/pkg/apis/application/v1alpha1/generated.pb.go b/pkg/apis/application/v1alpha1/generated.pb.go index f7d379625e576..6394d5712476f 100644 --- a/pkg/apis/application/v1alpha1/generated.pb.go +++ b/pkg/apis/application/v1alpha1/generated.pb.go @@ -33,7 +33,7 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package func (m *AWSAuthConfig) Reset() { *m = AWSAuthConfig{} } func (*AWSAuthConfig) ProtoMessage() {} func (*AWSAuthConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{0} + return fileDescriptor_generated_2473a92fb8cd7948, []int{0} } func (m *AWSAuthConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -61,7 +61,7 @@ var xxx_messageInfo_AWSAuthConfig proto.InternalMessageInfo func (m *AppProject) Reset() { *m = AppProject{} } func (*AppProject) ProtoMessage() {} func (*AppProject) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{1} + return fileDescriptor_generated_2473a92fb8cd7948, []int{1} } func (m *AppProject) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -89,7 +89,7 @@ var xxx_messageInfo_AppProject proto.InternalMessageInfo func (m *AppProjectList) Reset() { *m = AppProjectList{} } func (*AppProjectList) ProtoMessage() {} func (*AppProjectList) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{2} + return fileDescriptor_generated_2473a92fb8cd7948, []int{2} } func (m *AppProjectList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -117,7 +117,7 @@ var xxx_messageInfo_AppProjectList proto.InternalMessageInfo func (m *AppProjectSpec) Reset() { *m = AppProjectSpec{} } func (*AppProjectSpec) ProtoMessage() {} func (*AppProjectSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{3} + return fileDescriptor_generated_2473a92fb8cd7948, []int{3} } func (m *AppProjectSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -145,7 +145,7 @@ var xxx_messageInfo_AppProjectSpec proto.InternalMessageInfo func (m *Application) Reset() { *m = Application{} } func (*Application) ProtoMessage() {} func (*Application) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{4} + return fileDescriptor_generated_2473a92fb8cd7948, []int{4} } func (m *Application) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -173,7 +173,7 @@ var xxx_messageInfo_Application proto.InternalMessageInfo func (m *ApplicationCondition) Reset() { *m = ApplicationCondition{} } func (*ApplicationCondition) ProtoMessage() {} func (*ApplicationCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{5} + return fileDescriptor_generated_2473a92fb8cd7948, []int{5} } func (m *ApplicationCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -201,7 +201,7 @@ var xxx_messageInfo_ApplicationCondition proto.InternalMessageInfo func (m *ApplicationDestination) Reset() { *m = ApplicationDestination{} } func (*ApplicationDestination) ProtoMessage() {} func (*ApplicationDestination) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{6} + return fileDescriptor_generated_2473a92fb8cd7948, []int{6} } func (m *ApplicationDestination) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -229,7 +229,7 @@ var xxx_messageInfo_ApplicationDestination proto.InternalMessageInfo func (m *ApplicationList) Reset() { *m = ApplicationList{} } func (*ApplicationList) ProtoMessage() {} func (*ApplicationList) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{7} + return fileDescriptor_generated_2473a92fb8cd7948, []int{7} } func (m *ApplicationList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -257,7 +257,7 @@ var xxx_messageInfo_ApplicationList proto.InternalMessageInfo func (m *ApplicationSource) Reset() { *m = ApplicationSource{} } func (*ApplicationSource) ProtoMessage() {} func (*ApplicationSource) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{8} + return fileDescriptor_generated_2473a92fb8cd7948, []int{8} } func (m *ApplicationSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -285,7 +285,7 @@ var xxx_messageInfo_ApplicationSource proto.InternalMessageInfo func (m *ApplicationSourceDirectory) Reset() { *m = ApplicationSourceDirectory{} } func (*ApplicationSourceDirectory) ProtoMessage() {} func (*ApplicationSourceDirectory) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{9} + return fileDescriptor_generated_2473a92fb8cd7948, []int{9} } func (m *ApplicationSourceDirectory) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -313,7 +313,7 @@ var xxx_messageInfo_ApplicationSourceDirectory proto.InternalMessageInfo func (m *ApplicationSourceHelm) Reset() { *m = ApplicationSourceHelm{} } func (*ApplicationSourceHelm) ProtoMessage() {} func (*ApplicationSourceHelm) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{10} + return fileDescriptor_generated_2473a92fb8cd7948, []int{10} } func (m *ApplicationSourceHelm) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -341,7 +341,7 @@ var xxx_messageInfo_ApplicationSourceHelm proto.InternalMessageInfo func (m *ApplicationSourceJsonnet) Reset() { *m = ApplicationSourceJsonnet{} } func (*ApplicationSourceJsonnet) ProtoMessage() {} func (*ApplicationSourceJsonnet) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{11} + return fileDescriptor_generated_2473a92fb8cd7948, []int{11} } func (m *ApplicationSourceJsonnet) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -369,7 +369,7 @@ var xxx_messageInfo_ApplicationSourceJsonnet proto.InternalMessageInfo func (m *ApplicationSourceKsonnet) Reset() { *m = ApplicationSourceKsonnet{} } func (*ApplicationSourceKsonnet) ProtoMessage() {} func (*ApplicationSourceKsonnet) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{12} + return fileDescriptor_generated_2473a92fb8cd7948, []int{12} } func (m *ApplicationSourceKsonnet) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -397,7 +397,7 @@ var xxx_messageInfo_ApplicationSourceKsonnet proto.InternalMessageInfo func (m *ApplicationSourceKustomize) Reset() { *m = ApplicationSourceKustomize{} } func (*ApplicationSourceKustomize) ProtoMessage() {} func (*ApplicationSourceKustomize) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{13} + return fileDescriptor_generated_2473a92fb8cd7948, []int{13} } func (m *ApplicationSourceKustomize) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -425,7 +425,7 @@ var xxx_messageInfo_ApplicationSourceKustomize proto.InternalMessageInfo func (m *ApplicationSourcePlugin) Reset() { *m = ApplicationSourcePlugin{} } func (*ApplicationSourcePlugin) ProtoMessage() {} func (*ApplicationSourcePlugin) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{14} + return fileDescriptor_generated_2473a92fb8cd7948, []int{14} } func (m *ApplicationSourcePlugin) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -453,7 +453,7 @@ var xxx_messageInfo_ApplicationSourcePlugin proto.InternalMessageInfo func (m *ApplicationSpec) Reset() { *m = ApplicationSpec{} } func (*ApplicationSpec) ProtoMessage() {} func (*ApplicationSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{15} + return fileDescriptor_generated_2473a92fb8cd7948, []int{15} } func (m *ApplicationSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -481,7 +481,7 @@ var xxx_messageInfo_ApplicationSpec proto.InternalMessageInfo func (m *ApplicationStatus) Reset() { *m = ApplicationStatus{} } func (*ApplicationStatus) ProtoMessage() {} func (*ApplicationStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{16} + return fileDescriptor_generated_2473a92fb8cd7948, []int{16} } func (m *ApplicationStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -509,7 +509,7 @@ var xxx_messageInfo_ApplicationStatus proto.InternalMessageInfo func (m *ApplicationSummary) Reset() { *m = ApplicationSummary{} } func (*ApplicationSummary) ProtoMessage() {} func (*ApplicationSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{17} + return fileDescriptor_generated_2473a92fb8cd7948, []int{17} } func (m *ApplicationSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -537,7 +537,7 @@ var xxx_messageInfo_ApplicationSummary proto.InternalMessageInfo func (m *ApplicationTree) Reset() { *m = ApplicationTree{} } func (*ApplicationTree) ProtoMessage() {} func (*ApplicationTree) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{18} + return fileDescriptor_generated_2473a92fb8cd7948, []int{18} } func (m *ApplicationTree) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -565,7 +565,7 @@ var xxx_messageInfo_ApplicationTree proto.InternalMessageInfo func (m *ApplicationWatchEvent) Reset() { *m = ApplicationWatchEvent{} } func (*ApplicationWatchEvent) ProtoMessage() {} func (*ApplicationWatchEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{19} + return fileDescriptor_generated_2473a92fb8cd7948, []int{19} } func (m *ApplicationWatchEvent) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -593,7 +593,7 @@ var xxx_messageInfo_ApplicationWatchEvent proto.InternalMessageInfo func (m *Cluster) Reset() { *m = Cluster{} } func (*Cluster) ProtoMessage() {} func (*Cluster) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{20} + return fileDescriptor_generated_2473a92fb8cd7948, []int{20} } func (m *Cluster) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -621,7 +621,7 @@ var xxx_messageInfo_Cluster proto.InternalMessageInfo func (m *ClusterConfig) Reset() { *m = ClusterConfig{} } func (*ClusterConfig) ProtoMessage() {} func (*ClusterConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{21} + return fileDescriptor_generated_2473a92fb8cd7948, []int{21} } func (m *ClusterConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -649,7 +649,7 @@ var xxx_messageInfo_ClusterConfig proto.InternalMessageInfo func (m *ClusterList) Reset() { *m = ClusterList{} } func (*ClusterList) ProtoMessage() {} func (*ClusterList) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{22} + return fileDescriptor_generated_2473a92fb8cd7948, []int{22} } func (m *ClusterList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -677,7 +677,7 @@ var xxx_messageInfo_ClusterList proto.InternalMessageInfo func (m *Command) Reset() { *m = Command{} } func (*Command) ProtoMessage() {} func (*Command) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{23} + return fileDescriptor_generated_2473a92fb8cd7948, []int{23} } func (m *Command) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -705,7 +705,7 @@ var xxx_messageInfo_Command proto.InternalMessageInfo func (m *ComparedTo) Reset() { *m = ComparedTo{} } func (*ComparedTo) ProtoMessage() {} func (*ComparedTo) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{24} + return fileDescriptor_generated_2473a92fb8cd7948, []int{24} } func (m *ComparedTo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -733,7 +733,7 @@ var xxx_messageInfo_ComparedTo proto.InternalMessageInfo func (m *ComponentParameter) Reset() { *m = ComponentParameter{} } func (*ComponentParameter) ProtoMessage() {} func (*ComponentParameter) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{25} + return fileDescriptor_generated_2473a92fb8cd7948, []int{25} } func (m *ComponentParameter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -761,7 +761,7 @@ var xxx_messageInfo_ComponentParameter proto.InternalMessageInfo func (m *ConfigManagementPlugin) Reset() { *m = ConfigManagementPlugin{} } func (*ConfigManagementPlugin) ProtoMessage() {} func (*ConfigManagementPlugin) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{26} + return fileDescriptor_generated_2473a92fb8cd7948, []int{26} } func (m *ConfigManagementPlugin) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -789,7 +789,7 @@ var xxx_messageInfo_ConfigManagementPlugin proto.InternalMessageInfo func (m *ConnectionState) Reset() { *m = ConnectionState{} } func (*ConnectionState) ProtoMessage() {} func (*ConnectionState) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{27} + return fileDescriptor_generated_2473a92fb8cd7948, []int{27} } func (m *ConnectionState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -817,7 +817,7 @@ var xxx_messageInfo_ConnectionState proto.InternalMessageInfo func (m *EnvEntry) Reset() { *m = EnvEntry{} } func (*EnvEntry) ProtoMessage() {} func (*EnvEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{28} + return fileDescriptor_generated_2473a92fb8cd7948, []int{28} } func (m *EnvEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -845,7 +845,7 @@ var xxx_messageInfo_EnvEntry proto.InternalMessageInfo func (m *HealthStatus) Reset() { *m = HealthStatus{} } func (*HealthStatus) ProtoMessage() {} func (*HealthStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{29} + return fileDescriptor_generated_2473a92fb8cd7948, []int{29} } func (m *HealthStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -873,7 +873,7 @@ var xxx_messageInfo_HealthStatus proto.InternalMessageInfo func (m *HelmParameter) Reset() { *m = HelmParameter{} } func (*HelmParameter) ProtoMessage() {} func (*HelmParameter) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{30} + return fileDescriptor_generated_2473a92fb8cd7948, []int{30} } func (m *HelmParameter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -901,7 +901,7 @@ var xxx_messageInfo_HelmParameter proto.InternalMessageInfo func (m *HelmRepository) Reset() { *m = HelmRepository{} } func (*HelmRepository) ProtoMessage() {} func (*HelmRepository) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{31} + return fileDescriptor_generated_2473a92fb8cd7948, []int{31} } func (m *HelmRepository) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -929,7 +929,7 @@ var xxx_messageInfo_HelmRepository proto.InternalMessageInfo func (m *Info) Reset() { *m = Info{} } func (*Info) ProtoMessage() {} func (*Info) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{32} + return fileDescriptor_generated_2473a92fb8cd7948, []int{32} } func (m *Info) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -957,7 +957,7 @@ var xxx_messageInfo_Info proto.InternalMessageInfo func (m *InfoItem) Reset() { *m = InfoItem{} } func (*InfoItem) ProtoMessage() {} func (*InfoItem) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{33} + return fileDescriptor_generated_2473a92fb8cd7948, []int{33} } func (m *InfoItem) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -985,7 +985,7 @@ var xxx_messageInfo_InfoItem proto.InternalMessageInfo func (m *JWTToken) Reset() { *m = JWTToken{} } func (*JWTToken) ProtoMessage() {} func (*JWTToken) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{34} + return fileDescriptor_generated_2473a92fb8cd7948, []int{34} } func (m *JWTToken) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1013,7 +1013,7 @@ var xxx_messageInfo_JWTToken proto.InternalMessageInfo func (m *JsonnetVar) Reset() { *m = JsonnetVar{} } func (*JsonnetVar) ProtoMessage() {} func (*JsonnetVar) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{35} + return fileDescriptor_generated_2473a92fb8cd7948, []int{35} } func (m *JsonnetVar) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1041,7 +1041,7 @@ var xxx_messageInfo_JsonnetVar proto.InternalMessageInfo func (m *KsonnetParameter) Reset() { *m = KsonnetParameter{} } func (*KsonnetParameter) ProtoMessage() {} func (*KsonnetParameter) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{36} + return fileDescriptor_generated_2473a92fb8cd7948, []int{36} } func (m *KsonnetParameter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1069,7 +1069,7 @@ var xxx_messageInfo_KsonnetParameter proto.InternalMessageInfo func (m *KustomizeImageTag) Reset() { *m = KustomizeImageTag{} } func (*KustomizeImageTag) ProtoMessage() {} func (*KustomizeImageTag) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{37} + return fileDescriptor_generated_2473a92fb8cd7948, []int{37} } func (m *KustomizeImageTag) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1097,7 +1097,7 @@ var xxx_messageInfo_KustomizeImageTag proto.InternalMessageInfo func (m *Operation) Reset() { *m = Operation{} } func (*Operation) ProtoMessage() {} func (*Operation) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{38} + return fileDescriptor_generated_2473a92fb8cd7948, []int{38} } func (m *Operation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1125,7 +1125,7 @@ var xxx_messageInfo_Operation proto.InternalMessageInfo func (m *OperationState) Reset() { *m = OperationState{} } func (*OperationState) ProtoMessage() {} func (*OperationState) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{39} + return fileDescriptor_generated_2473a92fb8cd7948, []int{39} } func (m *OperationState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1153,7 +1153,7 @@ var xxx_messageInfo_OperationState proto.InternalMessageInfo func (m *ProjectRole) Reset() { *m = ProjectRole{} } func (*ProjectRole) ProtoMessage() {} func (*ProjectRole) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{40} + return fileDescriptor_generated_2473a92fb8cd7948, []int{40} } func (m *ProjectRole) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1181,7 +1181,7 @@ var xxx_messageInfo_ProjectRole proto.InternalMessageInfo func (m *Repository) Reset() { *m = Repository{} } func (*Repository) ProtoMessage() {} func (*Repository) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{41} + return fileDescriptor_generated_2473a92fb8cd7948, []int{41} } func (m *Repository) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1206,10 +1206,66 @@ func (m *Repository) XXX_DiscardUnknown() { var xxx_messageInfo_Repository proto.InternalMessageInfo +func (m *RepositoryCertificate) Reset() { *m = RepositoryCertificate{} } +func (*RepositoryCertificate) ProtoMessage() {} +func (*RepositoryCertificate) Descriptor() ([]byte, []int) { + return fileDescriptor_generated_2473a92fb8cd7948, []int{42} +} +func (m *RepositoryCertificate) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RepositoryCertificate) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (dst *RepositoryCertificate) XXX_Merge(src proto.Message) { + xxx_messageInfo_RepositoryCertificate.Merge(dst, src) +} +func (m *RepositoryCertificate) XXX_Size() int { + return m.Size() +} +func (m *RepositoryCertificate) XXX_DiscardUnknown() { + xxx_messageInfo_RepositoryCertificate.DiscardUnknown(m) +} + +var xxx_messageInfo_RepositoryCertificate proto.InternalMessageInfo + +func (m *RepositoryCertificateList) Reset() { *m = RepositoryCertificateList{} } +func (*RepositoryCertificateList) ProtoMessage() {} +func (*RepositoryCertificateList) Descriptor() ([]byte, []int) { + return fileDescriptor_generated_2473a92fb8cd7948, []int{43} +} +func (m *RepositoryCertificateList) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RepositoryCertificateList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalTo(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (dst *RepositoryCertificateList) XXX_Merge(src proto.Message) { + xxx_messageInfo_RepositoryCertificateList.Merge(dst, src) +} +func (m *RepositoryCertificateList) XXX_Size() int { + return m.Size() +} +func (m *RepositoryCertificateList) XXX_DiscardUnknown() { + xxx_messageInfo_RepositoryCertificateList.DiscardUnknown(m) +} + +var xxx_messageInfo_RepositoryCertificateList proto.InternalMessageInfo + func (m *RepositoryList) Reset() { *m = RepositoryList{} } func (*RepositoryList) ProtoMessage() {} func (*RepositoryList) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{42} + return fileDescriptor_generated_2473a92fb8cd7948, []int{44} } func (m *RepositoryList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1237,7 +1293,7 @@ var xxx_messageInfo_RepositoryList proto.InternalMessageInfo func (m *ResourceAction) Reset() { *m = ResourceAction{} } func (*ResourceAction) ProtoMessage() {} func (*ResourceAction) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{43} + return fileDescriptor_generated_2473a92fb8cd7948, []int{45} } func (m *ResourceAction) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1265,7 +1321,7 @@ var xxx_messageInfo_ResourceAction proto.InternalMessageInfo func (m *ResourceActionDefinition) Reset() { *m = ResourceActionDefinition{} } func (*ResourceActionDefinition) ProtoMessage() {} func (*ResourceActionDefinition) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{44} + return fileDescriptor_generated_2473a92fb8cd7948, []int{46} } func (m *ResourceActionDefinition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1293,7 +1349,7 @@ var xxx_messageInfo_ResourceActionDefinition proto.InternalMessageInfo func (m *ResourceActionParam) Reset() { *m = ResourceActionParam{} } func (*ResourceActionParam) ProtoMessage() {} func (*ResourceActionParam) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{45} + return fileDescriptor_generated_2473a92fb8cd7948, []int{47} } func (m *ResourceActionParam) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1321,7 +1377,7 @@ var xxx_messageInfo_ResourceActionParam proto.InternalMessageInfo func (m *ResourceActions) Reset() { *m = ResourceActions{} } func (*ResourceActions) ProtoMessage() {} func (*ResourceActions) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{46} + return fileDescriptor_generated_2473a92fb8cd7948, []int{48} } func (m *ResourceActions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1349,7 +1405,7 @@ var xxx_messageInfo_ResourceActions proto.InternalMessageInfo func (m *ResourceDiff) Reset() { *m = ResourceDiff{} } func (*ResourceDiff) ProtoMessage() {} func (*ResourceDiff) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{47} + return fileDescriptor_generated_2473a92fb8cd7948, []int{49} } func (m *ResourceDiff) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1377,7 +1433,7 @@ var xxx_messageInfo_ResourceDiff proto.InternalMessageInfo func (m *ResourceIgnoreDifferences) Reset() { *m = ResourceIgnoreDifferences{} } func (*ResourceIgnoreDifferences) ProtoMessage() {} func (*ResourceIgnoreDifferences) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{48} + return fileDescriptor_generated_2473a92fb8cd7948, []int{50} } func (m *ResourceIgnoreDifferences) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1405,7 +1461,7 @@ var xxx_messageInfo_ResourceIgnoreDifferences proto.InternalMessageInfo func (m *ResourceNetworkingInfo) Reset() { *m = ResourceNetworkingInfo{} } func (*ResourceNetworkingInfo) ProtoMessage() {} func (*ResourceNetworkingInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{49} + return fileDescriptor_generated_2473a92fb8cd7948, []int{51} } func (m *ResourceNetworkingInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1433,7 +1489,7 @@ var xxx_messageInfo_ResourceNetworkingInfo proto.InternalMessageInfo func (m *ResourceNode) Reset() { *m = ResourceNode{} } func (*ResourceNode) ProtoMessage() {} func (*ResourceNode) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{50} + return fileDescriptor_generated_2473a92fb8cd7948, []int{52} } func (m *ResourceNode) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1461,7 +1517,7 @@ var xxx_messageInfo_ResourceNode proto.InternalMessageInfo func (m *ResourceOverride) Reset() { *m = ResourceOverride{} } func (*ResourceOverride) ProtoMessage() {} func (*ResourceOverride) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{51} + return fileDescriptor_generated_2473a92fb8cd7948, []int{53} } func (m *ResourceOverride) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1489,7 +1545,7 @@ var xxx_messageInfo_ResourceOverride proto.InternalMessageInfo func (m *ResourceRef) Reset() { *m = ResourceRef{} } func (*ResourceRef) ProtoMessage() {} func (*ResourceRef) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{52} + return fileDescriptor_generated_2473a92fb8cd7948, []int{54} } func (m *ResourceRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1517,7 +1573,7 @@ var xxx_messageInfo_ResourceRef proto.InternalMessageInfo func (m *ResourceResult) Reset() { *m = ResourceResult{} } func (*ResourceResult) ProtoMessage() {} func (*ResourceResult) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{53} + return fileDescriptor_generated_2473a92fb8cd7948, []int{55} } func (m *ResourceResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1545,7 +1601,7 @@ var xxx_messageInfo_ResourceResult proto.InternalMessageInfo func (m *ResourceStatus) Reset() { *m = ResourceStatus{} } func (*ResourceStatus) ProtoMessage() {} func (*ResourceStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{54} + return fileDescriptor_generated_2473a92fb8cd7948, []int{56} } func (m *ResourceStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1573,7 +1629,7 @@ var xxx_messageInfo_ResourceStatus proto.InternalMessageInfo func (m *RevisionHistory) Reset() { *m = RevisionHistory{} } func (*RevisionHistory) ProtoMessage() {} func (*RevisionHistory) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{55} + return fileDescriptor_generated_2473a92fb8cd7948, []int{57} } func (m *RevisionHistory) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1601,7 +1657,7 @@ var xxx_messageInfo_RevisionHistory proto.InternalMessageInfo func (m *RevisionMetadata) Reset() { *m = RevisionMetadata{} } func (*RevisionMetadata) ProtoMessage() {} func (*RevisionMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{56} + return fileDescriptor_generated_2473a92fb8cd7948, []int{58} } func (m *RevisionMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1629,7 +1685,7 @@ var xxx_messageInfo_RevisionMetadata proto.InternalMessageInfo func (m *SyncOperation) Reset() { *m = SyncOperation{} } func (*SyncOperation) ProtoMessage() {} func (*SyncOperation) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{57} + return fileDescriptor_generated_2473a92fb8cd7948, []int{59} } func (m *SyncOperation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1657,7 +1713,7 @@ var xxx_messageInfo_SyncOperation proto.InternalMessageInfo func (m *SyncOperationResource) Reset() { *m = SyncOperationResource{} } func (*SyncOperationResource) ProtoMessage() {} func (*SyncOperationResource) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{58} + return fileDescriptor_generated_2473a92fb8cd7948, []int{60} } func (m *SyncOperationResource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1685,7 +1741,7 @@ var xxx_messageInfo_SyncOperationResource proto.InternalMessageInfo func (m *SyncOperationResult) Reset() { *m = SyncOperationResult{} } func (*SyncOperationResult) ProtoMessage() {} func (*SyncOperationResult) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{59} + return fileDescriptor_generated_2473a92fb8cd7948, []int{61} } func (m *SyncOperationResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1713,7 +1769,7 @@ var xxx_messageInfo_SyncOperationResult proto.InternalMessageInfo func (m *SyncPolicy) Reset() { *m = SyncPolicy{} } func (*SyncPolicy) ProtoMessage() {} func (*SyncPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{60} + return fileDescriptor_generated_2473a92fb8cd7948, []int{62} } func (m *SyncPolicy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1741,7 +1797,7 @@ var xxx_messageInfo_SyncPolicy proto.InternalMessageInfo func (m *SyncPolicyAutomated) Reset() { *m = SyncPolicyAutomated{} } func (*SyncPolicyAutomated) ProtoMessage() {} func (*SyncPolicyAutomated) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{61} + return fileDescriptor_generated_2473a92fb8cd7948, []int{63} } func (m *SyncPolicyAutomated) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1769,7 +1825,7 @@ var xxx_messageInfo_SyncPolicyAutomated proto.InternalMessageInfo func (m *SyncStatus) Reset() { *m = SyncStatus{} } func (*SyncStatus) ProtoMessage() {} func (*SyncStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{62} + return fileDescriptor_generated_2473a92fb8cd7948, []int{64} } func (m *SyncStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1797,7 +1853,7 @@ var xxx_messageInfo_SyncStatus proto.InternalMessageInfo func (m *SyncStrategy) Reset() { *m = SyncStrategy{} } func (*SyncStrategy) ProtoMessage() {} func (*SyncStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{63} + return fileDescriptor_generated_2473a92fb8cd7948, []int{65} } func (m *SyncStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1825,7 +1881,7 @@ var xxx_messageInfo_SyncStrategy proto.InternalMessageInfo func (m *SyncStrategyApply) Reset() { *m = SyncStrategyApply{} } func (*SyncStrategyApply) ProtoMessage() {} func (*SyncStrategyApply) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{64} + return fileDescriptor_generated_2473a92fb8cd7948, []int{66} } func (m *SyncStrategyApply) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1853,7 +1909,7 @@ var xxx_messageInfo_SyncStrategyApply proto.InternalMessageInfo func (m *SyncStrategyHook) Reset() { *m = SyncStrategyHook{} } func (*SyncStrategyHook) ProtoMessage() {} func (*SyncStrategyHook) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{65} + return fileDescriptor_generated_2473a92fb8cd7948, []int{67} } func (m *SyncStrategyHook) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1881,7 +1937,7 @@ var xxx_messageInfo_SyncStrategyHook proto.InternalMessageInfo func (m *TLSClientConfig) Reset() { *m = TLSClientConfig{} } func (*TLSClientConfig) ProtoMessage() {} func (*TLSClientConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_generated_39693ef384521064, []int{66} + return fileDescriptor_generated_2473a92fb8cd7948, []int{68} } func (m *TLSClientConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1950,6 +2006,8 @@ func init() { proto.RegisterType((*OperationState)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.OperationState") proto.RegisterType((*ProjectRole)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ProjectRole") proto.RegisterType((*Repository)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository") + proto.RegisterType((*RepositoryCertificate)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.RepositoryCertificate") + proto.RegisterType((*RepositoryCertificateList)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.RepositoryCertificateList") proto.RegisterType((*RepositoryList)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.RepositoryList") proto.RegisterType((*ResourceAction)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ResourceAction") proto.RegisterType((*ResourceActionDefinition)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ResourceActionDefinition") @@ -3764,10 +3822,18 @@ func (m *Repository) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0 } i++ + dAtA[i] = 0x38 + i++ + if m.Insecure { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i++ return i, nil } -func (m *RepositoryList) Marshal() (dAtA []byte, err error) { +func (m *RepositoryCertificate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalTo(dAtA) @@ -3777,7 +3843,47 @@ func (m *RepositoryList) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RepositoryList) MarshalTo(dAtA []byte) (int, error) { +func (m *RepositoryCertificate) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.ServerName))) + i += copy(dAtA[i:], m.ServerName) + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.CertType))) + i += copy(dAtA[i:], m.CertType) + dAtA[i] = 0x1a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.CertSubType))) + i += copy(dAtA[i:], m.CertSubType) + if m.CertData != nil { + dAtA[i] = 0x22 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.CertData))) + i += copy(dAtA[i:], m.CertData) + } + dAtA[i] = 0x2a + i++ + i = encodeVarintGenerated(dAtA, i, uint64(len(m.CertFingerprint))) + i += copy(dAtA[i:], m.CertFingerprint) + return i, nil +} + +func (m *RepositoryCertificateList) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RepositoryCertificateList) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int @@ -3805,6 +3911,44 @@ func (m *RepositoryList) MarshalTo(dAtA []byte) (int, error) { return i, nil } +func (m *RepositoryList) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RepositoryList) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + dAtA[i] = 0xa + i++ + i = encodeVarintGenerated(dAtA, i, uint64(m.ListMeta.Size())) + n42, err := m.ListMeta.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n42 + if len(m.Items) > 0 { + for _, msg := range m.Items { + dAtA[i] = 0x12 + i++ + i = encodeVarintGenerated(dAtA, i, uint64(msg.Size())) + n, err := msg.MarshalTo(dAtA[i:]) + if err != nil { + return 0, err + } + i += n + } + } + return i, nil +} + func (m *ResourceAction) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4147,11 +4291,11 @@ func (m *ResourceNode) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintGenerated(dAtA, i, uint64(m.ResourceRef.Size())) - n42, err := m.ResourceRef.MarshalTo(dAtA[i:]) + n43, err := m.ResourceRef.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n42 + i += n43 if len(m.ParentRefs) > 0 { for _, msg := range m.ParentRefs { dAtA[i] = 0x12 @@ -4180,11 +4324,11 @@ func (m *ResourceNode) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x22 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.NetworkingInfo.Size())) - n43, err := m.NetworkingInfo.MarshalTo(dAtA[i:]) + n44, err := m.NetworkingInfo.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n43 + i += n44 } dAtA[i] = 0x2a i++ @@ -4209,11 +4353,11 @@ func (m *ResourceNode) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x3a i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Health.Size())) - n44, err := m.Health.MarshalTo(dAtA[i:]) + n45, err := m.Health.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n44 + i += n45 } return i, nil } @@ -4391,11 +4535,11 @@ func (m *ResourceStatus) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x3a i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Health.Size())) - n45, err := m.Health.MarshalTo(dAtA[i:]) + n46, err := m.Health.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n45 + i += n46 } dAtA[i] = 0x40 i++ @@ -4438,22 +4582,22 @@ func (m *RevisionHistory) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x22 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.DeployedAt.Size())) - n46, err := m.DeployedAt.MarshalTo(dAtA[i:]) + n47, err := m.DeployedAt.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n46 + i += n47 dAtA[i] = 0x28 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.ID)) dAtA[i] = 0x32 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Source.Size())) - n47, err := m.Source.MarshalTo(dAtA[i:]) + n48, err := m.Source.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n47 + i += n48 return i, nil } @@ -4479,11 +4623,11 @@ func (m *RevisionMetadata) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Date.Size())) - n48, err := m.Date.MarshalTo(dAtA[i:]) + n49, err := m.Date.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n48 + i += n49 if len(m.Tags) > 0 { for _, s := range m.Tags { dAtA[i] = 0x1a @@ -4545,11 +4689,11 @@ func (m *SyncOperation) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x22 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.SyncStrategy.Size())) - n49, err := m.SyncStrategy.MarshalTo(dAtA[i:]) + n50, err := m.SyncStrategy.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n49 + i += n50 } if len(m.Resources) > 0 { for _, msg := range m.Resources { @@ -4567,11 +4711,11 @@ func (m *SyncOperation) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x3a i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Source.Size())) - n50, err := m.Source.MarshalTo(dAtA[i:]) + n51, err := m.Source.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n50 + i += n51 } if len(m.Manifests) > 0 { for _, s := range m.Manifests { @@ -4655,11 +4799,11 @@ func (m *SyncOperationResult) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x1a i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Source.Size())) - n51, err := m.Source.MarshalTo(dAtA[i:]) + n52, err := m.Source.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n51 + i += n52 return i, nil } @@ -4682,11 +4826,11 @@ func (m *SyncPolicy) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Automated.Size())) - n52, err := m.Automated.MarshalTo(dAtA[i:]) + n53, err := m.Automated.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n52 + i += n53 } return i, nil } @@ -4739,11 +4883,11 @@ func (m *SyncStatus) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0x12 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.ComparedTo.Size())) - n53, err := m.ComparedTo.MarshalTo(dAtA[i:]) + n54, err := m.ComparedTo.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n53 + i += n54 dAtA[i] = 0x1a i++ i = encodeVarintGenerated(dAtA, i, uint64(len(m.Revision))) @@ -4770,21 +4914,21 @@ func (m *SyncStrategy) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Apply.Size())) - n54, err := m.Apply.MarshalTo(dAtA[i:]) + n55, err := m.Apply.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n54 + i += n55 } if m.Hook != nil { dAtA[i] = 0x12 i++ i = encodeVarintGenerated(dAtA, i, uint64(m.Hook.Size())) - n55, err := m.Hook.MarshalTo(dAtA[i:]) + n56, err := m.Hook.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n55 + i += n56 } return i, nil } @@ -4833,11 +4977,11 @@ func (m *SyncStrategyHook) MarshalTo(dAtA []byte) (int, error) { dAtA[i] = 0xa i++ i = encodeVarintGenerated(dAtA, i, uint64(m.SyncStrategyApply.Size())) - n56, err := m.SyncStrategyApply.MarshalTo(dAtA[i:]) + n57, err := m.SyncStrategyApply.MarshalTo(dAtA[i:]) if err != nil { return 0, err } - i += n56 + i += n57 return i, nil } @@ -5573,6 +5717,39 @@ func (m *Repository) Size() (n int) { l = m.ConnectionState.Size() n += 1 + l + sovGenerated(uint64(l)) n += 2 + n += 2 + return n +} + +func (m *RepositoryCertificate) Size() (n int) { + var l int + _ = l + l = len(m.ServerName) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.CertType) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.CertSubType) + n += 1 + l + sovGenerated(uint64(l)) + if m.CertData != nil { + l = len(m.CertData) + n += 1 + l + sovGenerated(uint64(l)) + } + l = len(m.CertFingerprint) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *RepositoryCertificateList) Size() (n int) { + var l int + _ = l + l = m.ListMeta.Size() + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Items) > 0 { + for _, e := range m.Items { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -6539,6 +6716,32 @@ func (this *Repository) String() string { `SSHPrivateKey:` + fmt.Sprintf("%v", this.SSHPrivateKey) + `,`, `ConnectionState:` + strings.Replace(strings.Replace(this.ConnectionState.String(), "ConnectionState", "ConnectionState", 1), `&`, ``, 1) + `,`, `InsecureIgnoreHostKey:` + fmt.Sprintf("%v", this.InsecureIgnoreHostKey) + `,`, + `Insecure:` + fmt.Sprintf("%v", this.Insecure) + `,`, + `}`, + }, "") + return s +} +func (this *RepositoryCertificate) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&RepositoryCertificate{`, + `ServerName:` + fmt.Sprintf("%v", this.ServerName) + `,`, + `CertType:` + fmt.Sprintf("%v", this.CertType) + `,`, + `CertSubType:` + fmt.Sprintf("%v", this.CertSubType) + `,`, + `CertData:` + valueToStringGenerated(this.CertData) + `,`, + `CertFingerprint:` + fmt.Sprintf("%v", this.CertFingerprint) + `,`, + `}`, + }, "") + return s +} +func (this *RepositoryCertificateList) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&RepositoryCertificateList{`, + `ListMeta:` + strings.Replace(strings.Replace(this.ListMeta.String(), "ListMeta", "v1.ListMeta", 1), `&`, ``, 1) + `,`, + `Items:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Items), "RepositoryCertificate", "RepositoryCertificate", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -13085,6 +13288,334 @@ func (m *Repository) Unmarshal(dAtA []byte) error { } } m.InsecureIgnoreHostKey = bool(v != 0) + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Insecure", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.Insecure = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RepositoryCertificate) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RepositoryCertificate: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RepositoryCertificate: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServerName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + 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 ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServerName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CertType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + 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 ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CertType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CertSubType", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + 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 ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CertSubType = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CertData", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CertData = append(m.CertData[:0], dAtA[iNdEx:postIndex]...) + if m.CertData == nil { + m.CertData = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CertFingerprint", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + 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 ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CertFingerprint = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RepositoryCertificateList) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RepositoryCertificateList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RepositoryCertificateList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Items = append(m.Items, RepositoryCertificate{}) + if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -17502,274 +18033,282 @@ var ( ) func init() { - proto.RegisterFile("github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto", fileDescriptor_generated_39693ef384521064) -} - -var fileDescriptor_generated_39693ef384521064 = []byte{ - // 4236 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x3b, 0x5b, 0x8c, 0x1c, 0xd9, - 0x55, 0xae, 0x7e, 0xf7, 0x99, 0x87, 0x3d, 0x77, 0xd7, 0x9b, 0xce, 0x68, 0xd7, 0xb6, 0xca, 0x22, - 0xd9, 0x25, 0x49, 0x0f, 0x6b, 0x6d, 0xc0, 0x09, 0x12, 0xab, 0xe9, 0x19, 0x3f, 0xc6, 0x1e, 0x8f, - 0x67, 0x6f, 0x8f, 0x77, 0xa5, 0x25, 0x84, 0x2d, 0x57, 0xdf, 0xee, 0x2e, 0x4f, 0x77, 0x55, 0x6d, - 0x55, 0x75, 0xdb, 0xbd, 0xb0, 0x79, 0x80, 0x22, 0x41, 0x60, 0x23, 0x24, 0xc4, 0x57, 0x94, 0x0f, - 0xf2, 0xc7, 0x2a, 0x3f, 0xf0, 0x41, 0xfe, 0xf3, 0x01, 0xfb, 0x19, 0x50, 0x90, 0x56, 0x80, 0x2c, - 0x76, 0xc2, 0x07, 0x82, 0x0f, 0x84, 0x10, 0x3f, 0x16, 0x1f, 0xe8, 0xbe, 0x6f, 0xf5, 0xc3, 0xd3, - 0xe3, 0x2e, 0x3b, 0x22, 0xf9, 0xeb, 0xba, 0xe7, 0xd4, 0x39, 0xe7, 0x9e, 0x7b, 0xea, 0xbc, 0xee, - 0x69, 0xd8, 0xe9, 0x78, 0x49, 0x77, 0x70, 0xb7, 0xee, 0x06, 0xfd, 0x0d, 0x27, 0xea, 0x04, 0x61, - 0x14, 0xdc, 0x63, 0x3f, 0xbe, 0xe0, 0xb6, 0x36, 0xc2, 0xc3, 0xce, 0x86, 0x13, 0x7a, 0xf1, 0x86, - 0x13, 0x86, 0x3d, 0xcf, 0x75, 0x12, 0x2f, 0xf0, 0x37, 0x86, 0xaf, 0x3a, 0xbd, 0xb0, 0xeb, 0xbc, - 0xba, 0xd1, 0x21, 0x3e, 0x89, 0x9c, 0x84, 0xb4, 0xea, 0x61, 0x14, 0x24, 0x01, 0xfa, 0x92, 0x26, - 0x55, 0x97, 0xa4, 0xd8, 0x8f, 0xdf, 0x76, 0x5b, 0xf5, 0xf0, 0xb0, 0x53, 0xa7, 0xa4, 0xea, 0x06, - 0xa9, 0xba, 0x24, 0xb5, 0xfe, 0x05, 0x43, 0x8a, 0x4e, 0xd0, 0x09, 0x36, 0x18, 0xc5, 0xbb, 0x83, - 0x36, 0x7b, 0x62, 0x0f, 0xec, 0x17, 0xe7, 0xb4, 0x6e, 0x1f, 0x5e, 0x8e, 0xeb, 0x5e, 0x40, 0x65, - 0xdb, 0x70, 0x83, 0x88, 0x6c, 0x0c, 0x27, 0xa4, 0x59, 0x7f, 0x4d, 0xe3, 0xf4, 0x1d, 0xb7, 0xeb, - 0xf9, 0x24, 0x1a, 0xe9, 0x0d, 0xf5, 0x49, 0xe2, 0x4c, 0x7b, 0x6b, 0x63, 0xd6, 0x5b, 0xd1, 0xc0, - 0x4f, 0xbc, 0x3e, 0x99, 0x78, 0xe1, 0x57, 0x8f, 0x7b, 0x21, 0x76, 0xbb, 0xa4, 0xef, 0x8c, 0xbf, - 0x67, 0xbf, 0x0b, 0x2b, 0x9b, 0x6f, 0x35, 0x37, 0x07, 0x49, 0x77, 0x2b, 0xf0, 0xdb, 0x5e, 0x07, - 0x7d, 0x11, 0x96, 0xdc, 0xde, 0x20, 0x4e, 0x48, 0xb4, 0xe7, 0xf4, 0x49, 0xcd, 0xba, 0x60, 0xbd, - 0x5c, 0x6d, 0x3c, 0xf7, 0xd1, 0xc3, 0xf3, 0xa7, 0x8e, 0x1e, 0x9e, 0x5f, 0xda, 0xd2, 0x20, 0x6c, - 0xe2, 0xa1, 0x57, 0xa0, 0x1c, 0x05, 0x3d, 0xb2, 0x89, 0xf7, 0x6a, 0x39, 0xf6, 0xca, 0x69, 0xf1, - 0x4a, 0x19, 0xf3, 0x65, 0x2c, 0xe1, 0xf6, 0x3f, 0x59, 0x00, 0x9b, 0x61, 0xb8, 0x1f, 0x05, 0xf7, - 0x88, 0x9b, 0xa0, 0x77, 0xa0, 0x42, 0xb5, 0xd0, 0x72, 0x12, 0x87, 0x71, 0x5b, 0xba, 0xf4, 0x2b, - 0x75, 0xbe, 0x99, 0xba, 0xb9, 0x19, 0x7d, 0x72, 0x14, 0xbb, 0x3e, 0x7c, 0xb5, 0x7e, 0xfb, 0x2e, - 0x7d, 0xff, 0x16, 0x49, 0x9c, 0x06, 0x12, 0xcc, 0x40, 0xaf, 0x61, 0x45, 0x15, 0x1d, 0x42, 0x21, - 0x0e, 0x89, 0xcb, 0x04, 0x5b, 0xba, 0xb4, 0x53, 0x7f, 0x62, 0xfb, 0xa8, 0x6b, 0xb1, 0x9b, 0x21, - 0x71, 0x1b, 0xcb, 0x82, 0x6d, 0x81, 0x3e, 0x61, 0xc6, 0xc4, 0xfe, 0x47, 0x0b, 0x56, 0x35, 0xda, - 0xae, 0x17, 0x27, 0xe8, 0x2b, 0x13, 0x3b, 0xac, 0xcf, 0xb7, 0x43, 0xfa, 0x36, 0xdb, 0xdf, 0x19, - 0xc1, 0xa8, 0x22, 0x57, 0x8c, 0xdd, 0xdd, 0x83, 0xa2, 0x97, 0x90, 0x7e, 0x5c, 0xcb, 0x5d, 0xc8, - 0xbf, 0xbc, 0x74, 0xe9, 0x4a, 0x26, 0xdb, 0x6b, 0xac, 0x08, 0x8e, 0xc5, 0x1d, 0x4a, 0x1b, 0x73, - 0x16, 0xf6, 0x77, 0x8b, 0xe6, 0xe6, 0xe8, 0xae, 0xd1, 0xab, 0xb0, 0x14, 0x07, 0x83, 0xc8, 0x25, - 0x98, 0x84, 0x41, 0x5c, 0xb3, 0x2e, 0xe4, 0xe9, 0xe1, 0x53, 0x5b, 0x69, 0xea, 0x65, 0x6c, 0xe2, - 0xa0, 0x3f, 0xb2, 0x60, 0xb9, 0x45, 0xe2, 0xc4, 0xf3, 0x19, 0x7f, 0x29, 0xf9, 0x1b, 0x8b, 0x49, - 0x2e, 0x17, 0xb7, 0x35, 0xe5, 0xc6, 0xf3, 0x62, 0x17, 0xcb, 0xc6, 0x62, 0x8c, 0x53, 0xcc, 0xa9, - 0xc1, 0xb7, 0x48, 0xec, 0x46, 0x5e, 0x48, 0x9f, 0x6b, 0xf9, 0xb4, 0xc1, 0x6f, 0x6b, 0x10, 0x36, - 0xf1, 0xd0, 0x21, 0x14, 0xa9, 0x41, 0xc7, 0xb5, 0x02, 0x13, 0xfe, 0xea, 0x02, 0xc2, 0x0b, 0x75, - 0xd2, 0x0f, 0x45, 0xeb, 0x9d, 0x3e, 0xc5, 0x98, 0xf3, 0x40, 0x1f, 0x58, 0x50, 0x13, 0x5f, 0x1b, - 0x26, 0x5c, 0x95, 0x6f, 0x75, 0xbd, 0x84, 0xf4, 0xbc, 0x38, 0xa9, 0x15, 0x99, 0x00, 0x1b, 0xf3, - 0x99, 0xd4, 0xb5, 0x28, 0x18, 0x84, 0x37, 0x3d, 0xbf, 0xd5, 0xb8, 0x20, 0x38, 0xd5, 0xb6, 0x66, - 0x10, 0xc6, 0x33, 0x59, 0xa2, 0x3f, 0xb5, 0x60, 0xdd, 0x77, 0xfa, 0x24, 0x0e, 0x1d, 0x7a, 0xa8, - 0x1c, 0xdc, 0xe8, 0x39, 0xee, 0x21, 0x93, 0xa8, 0xf4, 0x64, 0x12, 0xd9, 0x42, 0xa2, 0xf5, 0xbd, - 0x99, 0xa4, 0xf1, 0x63, 0xd8, 0xda, 0x7f, 0x93, 0x87, 0x25, 0xc3, 0x10, 0x9e, 0x81, 0x67, 0xe9, - 0xa5, 0x3c, 0xcb, 0x8d, 0x6c, 0x0c, 0x78, 0x96, 0x6b, 0x41, 0x09, 0x94, 0xe2, 0xc4, 0x49, 0x06, - 0x31, 0x33, 0xd2, 0xa5, 0x4b, 0xbb, 0x19, 0xf1, 0x63, 0x34, 0x1b, 0xab, 0x82, 0x63, 0x89, 0x3f, - 0x63, 0xc1, 0x0b, 0xbd, 0x0b, 0xd5, 0x20, 0xa4, 0x31, 0x83, 0x7e, 0x1d, 0x05, 0xc6, 0x78, 0x7b, - 0x01, 0xc6, 0xb7, 0x25, 0xad, 0xc6, 0xca, 0xd1, 0xc3, 0xf3, 0x55, 0xf5, 0x88, 0x35, 0x17, 0xdb, - 0x85, 0xe7, 0x0d, 0xf9, 0xb6, 0x02, 0xbf, 0xe5, 0xb1, 0x03, 0xbd, 0x00, 0x85, 0x64, 0x14, 0xca, - 0xa0, 0xa4, 0x54, 0x74, 0x30, 0x0a, 0x09, 0x66, 0x10, 0x1a, 0x86, 0xfa, 0x24, 0x8e, 0x9d, 0x0e, - 0x19, 0x0f, 0x43, 0xb7, 0xf8, 0x32, 0x96, 0x70, 0xfb, 0x5d, 0x78, 0x61, 0xba, 0xd7, 0x40, 0x9f, - 0x81, 0x52, 0x4c, 0xa2, 0x21, 0x89, 0x04, 0x23, 0xad, 0x19, 0xb6, 0x8a, 0x05, 0x14, 0x6d, 0x40, - 0x55, 0x59, 0xa3, 0x60, 0xb7, 0x26, 0x50, 0xab, 0xda, 0x84, 0x35, 0x8e, 0xfd, 0xcf, 0x16, 0x9c, - 0x36, 0x78, 0x3e, 0x83, 0xe0, 0x70, 0x98, 0x0e, 0x0e, 0x57, 0xb3, 0xb1, 0x98, 0x19, 0xd1, 0xe1, - 0x3b, 0x25, 0x58, 0x33, 0xed, 0x8a, 0x7d, 0x9e, 0x2c, 0x33, 0x20, 0x61, 0x70, 0x07, 0xef, 0x0a, - 0x75, 0xea, 0xcc, 0x80, 0x2f, 0x63, 0x09, 0xa7, 0xe7, 0x1b, 0x3a, 0x49, 0x57, 0xe8, 0x52, 0x9d, - 0xef, 0xbe, 0x93, 0x74, 0x31, 0x83, 0xa0, 0xdf, 0x80, 0xd5, 0xc4, 0x89, 0x3a, 0x24, 0xc1, 0x64, - 0xe8, 0xc5, 0xd2, 0x22, 0xab, 0x8d, 0x17, 0x04, 0xee, 0xea, 0x41, 0x0a, 0x8a, 0xc7, 0xb0, 0x91, - 0x0f, 0x85, 0x2e, 0xe9, 0xf5, 0x6b, 0x65, 0xa6, 0xe9, 0xfd, 0x8c, 0x3e, 0x20, 0xb6, 0xd1, 0xeb, - 0xa4, 0xd7, 0x6f, 0x54, 0xa8, 0xbc, 0xf4, 0x17, 0x66, 0x7c, 0xd0, 0xef, 0x59, 0x50, 0x3d, 0x1c, - 0xc4, 0x49, 0xd0, 0xf7, 0xde, 0x23, 0xb5, 0x0a, 0xe3, 0x7a, 0x27, 0x4b, 0xae, 0x37, 0x25, 0x71, - 0xfe, 0x39, 0xa9, 0x47, 0xac, 0xd9, 0xa2, 0xf7, 0xa0, 0x7c, 0x18, 0x07, 0xbe, 0x4f, 0x92, 0x5a, - 0x95, 0x49, 0xd0, 0xcc, 0x54, 0x02, 0x4e, 0xba, 0xb1, 0x44, 0x8f, 0x54, 0x3c, 0x60, 0xc9, 0x90, - 0x29, 0xa0, 0xe5, 0x45, 0xc4, 0x4d, 0x82, 0x68, 0x54, 0x83, 0xec, 0x15, 0xb0, 0x2d, 0x89, 0x73, - 0x05, 0xa8, 0x47, 0xac, 0xd9, 0xa2, 0x21, 0x94, 0xc2, 0xde, 0xa0, 0xe3, 0xf9, 0xb5, 0x25, 0x26, - 0x00, 0xce, 0x52, 0x80, 0x7d, 0x46, 0xb9, 0x01, 0xd4, 0x41, 0xf0, 0xdf, 0x58, 0x70, 0xb3, 0xff, - 0xd6, 0x82, 0xf5, 0xd9, 0x02, 0xf3, 0x2f, 0xc3, 0x1d, 0x44, 0x31, 0xf7, 0x68, 0x15, 0xf3, 0xcb, - 0x60, 0xcb, 0x58, 0xc2, 0xd1, 0xd7, 0xa0, 0x7c, 0x4f, 0x1c, 0x61, 0x2e, 0xfb, 0x23, 0xbc, 0x21, - 0x8e, 0x50, 0xf1, 0xbf, 0x21, 0x8f, 0x51, 0x30, 0xb5, 0xff, 0xd7, 0x82, 0xb3, 0x53, 0x2d, 0x1e, - 0xd5, 0x01, 0x86, 0x4e, 0x6f, 0x40, 0xae, 0x7a, 0x34, 0x19, 0xe2, 0xe9, 0xdf, 0x2a, 0x0d, 0x98, - 0x6f, 0xaa, 0x55, 0x6c, 0x60, 0xa0, 0xdf, 0x05, 0x08, 0x9d, 0xc8, 0xe9, 0x93, 0x84, 0x44, 0xd2, - 0x2d, 0x5d, 0x5f, 0x60, 0x33, 0x54, 0x88, 0x7d, 0x49, 0x50, 0x87, 0x6b, 0xb5, 0x14, 0x63, 0x83, - 0x1f, 0x4d, 0xf6, 0x22, 0xd2, 0x23, 0x4e, 0x4c, 0x58, 0x75, 0x33, 0x96, 0xec, 0x61, 0x0d, 0xc2, - 0x26, 0x9e, 0xfd, 0x3f, 0x16, 0xd4, 0x66, 0x69, 0x0d, 0x85, 0x50, 0x26, 0x0f, 0x92, 0x37, 0x9d, - 0x88, 0x6f, 0x7f, 0xb1, 0x14, 0x5c, 0x10, 0x7d, 0xd3, 0x89, 0xf4, 0x69, 0x5c, 0xe1, 0xd4, 0xb1, - 0x64, 0x83, 0x3a, 0x50, 0x48, 0x7a, 0x4e, 0x16, 0x19, 0xbf, 0xc1, 0x4e, 0x87, 0xd3, 0xdd, 0xcd, - 0x18, 0x33, 0x06, 0xf6, 0xdf, 0x4f, 0xdb, 0xb7, 0xf8, 0xc6, 0xa9, 0x2e, 0x89, 0x3f, 0xf4, 0xa2, - 0xc0, 0xef, 0x13, 0x3f, 0x19, 0xaf, 0x14, 0xaf, 0x68, 0x10, 0x36, 0xf1, 0xd0, 0xd7, 0xa7, 0x18, - 0xc0, 0xcd, 0x05, 0xb6, 0x20, 0xc4, 0x99, 0xdb, 0x06, 0xec, 0x8f, 0xf3, 0x53, 0xbe, 0x4a, 0xe5, - 0x38, 0xd1, 0x25, 0x00, 0x1a, 0xb1, 0xf7, 0x23, 0xd2, 0xf6, 0x1e, 0x88, 0x5d, 0x29, 0x92, 0x7b, - 0x0a, 0x82, 0x0d, 0x2c, 0xf4, 0x3e, 0x54, 0xbd, 0xbe, 0xd3, 0x21, 0x07, 0x4e, 0x47, 0x6e, 0x69, - 0x91, 0xe4, 0x4c, 0x09, 0xb3, 0x23, 0x88, 0xea, 0xbc, 0x42, 0xae, 0xc4, 0x58, 0x73, 0x44, 0x36, - 0x94, 0xd8, 0x03, 0x4d, 0x0c, 0xe9, 0xf7, 0xc7, 0x7c, 0x11, 0xc3, 0x8c, 0xb1, 0x80, 0xa0, 0x3f, - 0xb7, 0x60, 0xd9, 0x0d, 0xfa, 0xfd, 0xc0, 0xdf, 0x75, 0xee, 0x92, 0x9e, 0xac, 0x5b, 0x3a, 0x4f, - 0x25, 0x18, 0xd5, 0xb7, 0x0c, 0x4e, 0x57, 0xfc, 0x24, 0x1a, 0xe9, 0x52, 0xcc, 0x04, 0xe1, 0x94, - 0x48, 0xeb, 0xaf, 0xc3, 0xda, 0xc4, 0x8b, 0xe8, 0x0c, 0xe4, 0x0f, 0xc9, 0x88, 0x1f, 0x04, 0xa6, - 0x3f, 0xd1, 0xf3, 0x50, 0x64, 0x0e, 0x85, 0xe7, 0x09, 0x98, 0x3f, 0x7c, 0x39, 0x77, 0xd9, 0xb2, - 0xbf, 0x6b, 0xc1, 0xa7, 0x66, 0x38, 0x68, 0x9a, 0x5c, 0xf8, 0xba, 0xa3, 0xa1, 0xac, 0x9d, 0x7d, - 0xec, 0x0c, 0x82, 0xbe, 0x0a, 0x79, 0xe2, 0x0f, 0xc5, 0xf9, 0x6d, 0x2d, 0xa0, 0x98, 0x2b, 0xfe, - 0x90, 0x6f, 0xba, 0x7c, 0xf4, 0xf0, 0x7c, 0xfe, 0x8a, 0x3f, 0xc4, 0x94, 0xb0, 0xfd, 0xc3, 0x62, - 0x2a, 0xfd, 0x6b, 0xca, 0x9c, 0x9e, 0x49, 0x29, 0x92, 0xbf, 0xdd, 0x2c, 0xcf, 0xc3, 0xc8, 0x5c, - 0x79, 0xf9, 0x2d, 0x78, 0xa1, 0x3f, 0xb0, 0x58, 0xd1, 0x2b, 0x33, 0x5e, 0x11, 0x53, 0x9e, 0x42, - 0x01, 0x6e, 0xd6, 0xd1, 0x72, 0x11, 0x9b, 0xac, 0x69, 0x10, 0x0c, 0x79, 0xfd, 0x2b, 0xbc, 0xb1, - 0x72, 0x7b, 0xb2, 0x2c, 0x96, 0x70, 0x34, 0x00, 0x88, 0x47, 0xbe, 0xbb, 0x1f, 0xf4, 0x3c, 0x77, - 0x24, 0x4a, 0x91, 0x45, 0x9c, 0x5f, 0x53, 0x11, 0xe3, 0x11, 0x4b, 0x3f, 0x63, 0x83, 0x11, 0xfa, - 0x9e, 0x05, 0x6b, 0x5e, 0xc7, 0x0f, 0x22, 0xb2, 0xed, 0xb5, 0xdb, 0x24, 0x22, 0xbe, 0x4b, 0x62, - 0x51, 0x75, 0x1f, 0x2c, 0xc0, 0x5e, 0x16, 0xb0, 0x3b, 0xe3, 0xb4, 0x1b, 0x9f, 0x16, 0x2a, 0x58, - 0x9b, 0x00, 0xe1, 0x49, 0x49, 0x90, 0x03, 0x05, 0xcf, 0x6f, 0x07, 0xa2, 0xea, 0x7e, 0x7d, 0x01, - 0x89, 0x76, 0xfc, 0x76, 0xa0, 0xbf, 0x0c, 0xfa, 0x84, 0x19, 0x69, 0xfb, 0xbf, 0x2b, 0xe9, 0xcc, - 0x9e, 0x57, 0x86, 0xef, 0x41, 0x35, 0x12, 0x7b, 0x90, 0xa1, 0x6f, 0x27, 0x03, 0x7d, 0x88, 0x7a, - 0x54, 0xb9, 0x3c, 0xb9, 0x1e, 0x63, 0xcd, 0x8e, 0x86, 0x40, 0x7a, 0x44, 0xc2, 0x72, 0x17, 0xb5, - 0x02, 0xc1, 0x52, 0x17, 0xdd, 0x23, 0x9f, 0x16, 0xdd, 0x23, 0xdf, 0x45, 0x01, 0x94, 0xba, 0xc4, - 0xe9, 0x25, 0x5d, 0x51, 0x74, 0x5f, 0x5b, 0x28, 0x57, 0xa1, 0x84, 0xc6, 0xeb, 0x6d, 0xbe, 0x8a, - 0x05, 0x1b, 0x34, 0x80, 0x72, 0xd7, 0x8b, 0x59, 0xba, 0xcc, 0x5d, 0xf4, 0x8d, 0x85, 0x74, 0xca, - 0x0b, 0x9f, 0xeb, 0x9c, 0xa2, 0xfe, 0xb8, 0xc4, 0x02, 0x96, 0xbc, 0xd0, 0xef, 0x5b, 0x00, 0xae, - 0xac, 0xb4, 0xa5, 0x79, 0xdf, 0xce, 0xc6, 0x23, 0xa8, 0x0a, 0x5e, 0x07, 0x52, 0xb5, 0x14, 0x63, - 0x83, 0x2d, 0x7a, 0x07, 0x96, 0x23, 0xe2, 0x06, 0xbe, 0xeb, 0xf5, 0x48, 0x6b, 0x33, 0xa9, 0x95, - 0x98, 0xce, 0x7f, 0x79, 0xbe, 0x8a, 0xf8, 0xc0, 0xeb, 0x93, 0xc6, 0x19, 0x1a, 0x63, 0xb0, 0x41, - 0x03, 0xa7, 0x28, 0xa2, 0x6f, 0x59, 0xb0, 0xaa, 0x3a, 0x0d, 0xf4, 0x28, 0x88, 0x28, 0x06, 0x77, - 0xb2, 0x68, 0x6a, 0x30, 0x82, 0x0d, 0x44, 0x2b, 0xd1, 0xf4, 0x1a, 0x1e, 0x63, 0x8a, 0xde, 0x06, - 0x08, 0xee, 0xb2, 0x46, 0x02, 0xdd, 0x67, 0xe5, 0xc4, 0xfb, 0x5c, 0xe5, 0x4d, 0x29, 0x49, 0x01, - 0x1b, 0xd4, 0xd0, 0x4d, 0x00, 0xfe, 0x9d, 0x1c, 0x8c, 0x42, 0xc2, 0x6a, 0xbe, 0x6a, 0xe3, 0x73, - 0x52, 0xf3, 0x4d, 0x05, 0x79, 0xf4, 0xf0, 0xfc, 0x64, 0x52, 0xcf, 0x9a, 0x29, 0xc6, 0xeb, 0xe8, - 0x01, 0x94, 0xe3, 0x41, 0xbf, 0xef, 0xa8, 0xf2, 0xed, 0x56, 0x46, 0x21, 0x8a, 0x13, 0xd5, 0x26, - 0x29, 0x16, 0xb0, 0x64, 0x67, 0xfb, 0x80, 0x26, 0xf1, 0xd1, 0x6b, 0xb0, 0x4c, 0x1e, 0x24, 0x24, - 0xf2, 0x9d, 0xde, 0x1d, 0xbc, 0x2b, 0x4b, 0x0e, 0x76, 0xec, 0x57, 0x8c, 0x75, 0x9c, 0xc2, 0x32, - 0x52, 0xa4, 0xdc, 0xac, 0x14, 0xc9, 0xfe, 0x7a, 0x2a, 0x3c, 0x1f, 0x44, 0x84, 0xa0, 0x1e, 0x14, - 0xfd, 0xa0, 0xa5, 0xdc, 0xdb, 0xb5, 0x0c, 0xdc, 0xdb, 0x5e, 0xd0, 0x32, 0xda, 0xbc, 0xf4, 0x29, - 0xc6, 0x9c, 0x89, 0xfd, 0xd3, 0x74, 0x95, 0xf5, 0x96, 0x93, 0xb8, 0xdd, 0x2b, 0x43, 0x9a, 0x34, - 0xdf, 0x4c, 0x75, 0xbe, 0x7e, 0xcd, 0xec, 0x7c, 0x3d, 0x7a, 0x78, 0xfe, 0xb3, 0xb3, 0x2e, 0x7f, - 0xee, 0x53, 0x0a, 0x75, 0x46, 0xc2, 0x68, 0x92, 0xbd, 0x0f, 0x4b, 0x86, 0x84, 0xc2, 0x85, 0x66, - 0xd5, 0x1a, 0x52, 0x11, 0xdf, 0x58, 0xc4, 0x26, 0x3f, 0xfb, 0x1f, 0x72, 0x50, 0x16, 0x3d, 0xe7, - 0xb9, 0x5b, 0x6d, 0x32, 0x79, 0xcb, 0xcd, 0x4c, 0xde, 0x42, 0x28, 0xb9, 0xec, 0x06, 0x4b, 0xf8, - 0xe9, 0x45, 0x6a, 0x4a, 0x21, 0x1d, 0xbf, 0x11, 0xd3, 0x32, 0xf1, 0x67, 0x2c, 0xf8, 0xa0, 0x0f, - 0x2c, 0x38, 0xed, 0xd2, 0xda, 0xc3, 0xd5, 0xae, 0xa4, 0xb0, 0x70, 0x23, 0x78, 0x2b, 0x4d, 0xb1, - 0xf1, 0x29, 0xc1, 0xfd, 0xf4, 0x18, 0x00, 0x8f, 0xf3, 0xb6, 0xff, 0x3a, 0x0f, 0x2b, 0x29, 0xc9, - 0xd1, 0xe7, 0xa1, 0x32, 0x88, 0xe9, 0x37, 0xa0, 0xd2, 0x5e, 0xd5, 0x2b, 0xbc, 0x23, 0xd6, 0xb1, - 0xc2, 0xa0, 0xd8, 0xa1, 0x13, 0xc7, 0xf7, 0x83, 0xa8, 0x25, 0xf4, 0xac, 0xb0, 0xf7, 0xc5, 0x3a, - 0x56, 0x18, 0xb4, 0xfa, 0xbb, 0x4b, 0x9c, 0x88, 0x44, 0x07, 0xc1, 0x21, 0x99, 0xb8, 0x36, 0x69, - 0x68, 0x10, 0x36, 0xf1, 0x98, 0xd2, 0x92, 0x5e, 0xbc, 0xd5, 0xf3, 0x88, 0x9f, 0x70, 0x31, 0x33, - 0x50, 0xda, 0xc1, 0x6e, 0xd3, 0xa4, 0xa8, 0x95, 0x36, 0x06, 0xc0, 0xe3, 0xbc, 0xd1, 0x37, 0x2d, - 0x58, 0x71, 0xee, 0xc7, 0xfa, 0x02, 0xb4, 0x56, 0x5c, 0xd8, 0x7c, 0x52, 0x17, 0xaa, 0x8d, 0xb5, - 0xa3, 0x87, 0xe7, 0xd3, 0x77, 0xac, 0x38, 0xcd, 0xd1, 0xfe, 0x89, 0x05, 0xf2, 0x62, 0xf5, 0x19, - 0xb4, 0x84, 0x3b, 0xe9, 0x96, 0x70, 0x63, 0xf1, 0xef, 0x64, 0x46, 0x3b, 0x78, 0x0f, 0xca, 0xb4, - 0x9a, 0x73, 0xfc, 0x16, 0xfa, 0x25, 0x28, 0xbb, 0xfc, 0xa7, 0x70, 0xd7, 0xac, 0x59, 0x28, 0xa0, - 0x58, 0xc2, 0xd0, 0x8b, 0x50, 0x70, 0xa2, 0x8e, 0x74, 0xd1, 0xac, 0x97, 0xba, 0x19, 0x75, 0x62, - 0xcc, 0x56, 0xed, 0x0f, 0x72, 0x00, 0x5b, 0x41, 0x3f, 0x74, 0x22, 0xd2, 0x3a, 0x08, 0x7e, 0xe1, - 0x2b, 0x27, 0xfb, 0x8f, 0x2d, 0x40, 0x54, 0x1f, 0x81, 0x4f, 0x7c, 0xdd, 0xfe, 0x40, 0x1b, 0x50, - 0x75, 0xe5, 0xaa, 0xf8, 0xea, 0x55, 0x2a, 0xad, 0xd0, 0xb1, 0xc6, 0x99, 0xc3, 0xb7, 0x5e, 0x94, - 0x05, 0x37, 0xff, 0xca, 0xd5, 0x71, 0xb3, 0x16, 0x9f, 0xa8, 0xbf, 0xed, 0xef, 0xe4, 0xe0, 0x05, - 0x6e, 0xd0, 0xb7, 0x1c, 0xdf, 0xe9, 0x90, 0x3e, 0x95, 0x6a, 0xde, 0xd2, 0xfb, 0x1d, 0x5a, 0xc3, - 0x78, 0xb2, 0xb9, 0xb9, 0x90, 0x4d, 0x72, 0x5b, 0xe2, 0xd6, 0xb3, 0xe3, 0x7b, 0x09, 0x66, 0x94, - 0x51, 0x08, 0x15, 0x39, 0xfb, 0x20, 0x22, 0x44, 0x16, 0x5c, 0xd4, 0x87, 0x76, 0x4d, 0xd0, 0xc6, - 0x8a, 0x8b, 0xfd, 0x23, 0x0b, 0xc6, 0x9d, 0x36, 0x8b, 0x77, 0xfc, 0x0a, 0x6f, 0x3c, 0xde, 0xa5, - 0x2f, 0xdd, 0xe6, 0xbf, 0xc7, 0x42, 0x5f, 0x81, 0x25, 0x27, 0x49, 0x48, 0x3f, 0x4c, 0x58, 0x26, - 0x99, 0x7f, 0xb2, 0x4c, 0xf2, 0x56, 0xd0, 0xf2, 0xda, 0x1e, 0xcb, 0x24, 0x4d, 0x72, 0xf6, 0x1b, - 0x50, 0x91, 0xdd, 0x8c, 0x39, 0x8e, 0xf1, 0x62, 0xaa, 0x33, 0x33, 0xc3, 0x50, 0x1c, 0x58, 0x36, - 0x0b, 0xa1, 0xa7, 0xa0, 0x13, 0xfb, 0x03, 0x0b, 0x56, 0x52, 0x8d, 0xe1, 0x8c, 0x64, 0xa7, 0x51, - 0xaf, 0x1d, 0xb0, 0x1a, 0x35, 0xf2, 0x7c, 0x9e, 0x6a, 0x54, 0xf4, 0xa7, 0x7a, 0x55, 0x83, 0xb0, - 0x89, 0x67, 0x7f, 0x3f, 0x07, 0xab, 0xec, 0x56, 0x88, 0x84, 0x41, 0xec, 0xb1, 0x7a, 0xeb, 0x25, - 0xc8, 0x0f, 0xa2, 0x9e, 0x90, 0x67, 0x49, 0x50, 0xc8, 0xdf, 0xc1, 0xbb, 0x98, 0xae, 0xcf, 0xf1, - 0x51, 0xda, 0x50, 0x72, 0x9d, 0x6d, 0x1a, 0x23, 0xa8, 0x14, 0xcb, 0x3c, 0xa3, 0xdd, 0xda, 0xa4, - 0x2b, 0x58, 0x40, 0xd0, 0xcb, 0x50, 0x71, 0x49, 0x94, 0x30, 0xac, 0x02, 0xc3, 0x5a, 0xa6, 0xc6, - 0xba, 0x25, 0xd6, 0xb0, 0x82, 0x52, 0x0f, 0x7d, 0x48, 0x46, 0x0c, 0xb1, 0xc8, 0x10, 0xf9, 0x75, - 0x0e, 0x5f, 0xc2, 0x12, 0x96, 0xca, 0x28, 0x4a, 0x27, 0xca, 0x28, 0xca, 0xc7, 0x65, 0x14, 0xf6, - 0x2d, 0x60, 0x2d, 0x87, 0xac, 0xcc, 0xec, 0x0d, 0xa8, 0x50, 0x72, 0x34, 0x24, 0x65, 0x45, 0xb2, - 0x09, 0x95, 0x1b, 0x6f, 0x1d, 0xf0, 0x44, 0xc6, 0x86, 0xbc, 0xe7, 0x70, 0x07, 0x9b, 0xd7, 0xdb, - 0xda, 0x89, 0xe3, 0x01, 0xfb, 0x88, 0x28, 0x10, 0x5d, 0x84, 0x3c, 0x79, 0x10, 0x32, 0x92, 0x79, - 0xed, 0x84, 0xaf, 0x3c, 0x08, 0xbd, 0x88, 0xc4, 0x14, 0x89, 0x3c, 0x08, 0xed, 0x01, 0x80, 0xee, - 0xc2, 0x67, 0x65, 0xa7, 0x17, 0xa0, 0xe0, 0x06, 0x2d, 0x22, 0x0c, 0x54, 0x91, 0xd9, 0x0a, 0x5a, - 0x04, 0x33, 0x88, 0xfd, 0x6d, 0x0b, 0xce, 0x8c, 0xb7, 0xce, 0x7f, 0x66, 0xb1, 0xe3, 0x6d, 0x58, - 0x9b, 0xe8, 0x79, 0x67, 0x75, 0x68, 0x31, 0xe8, 0x21, 0x03, 0xd4, 0x16, 0x6d, 0x23, 0x6b, 0xe1, - 0x24, 0xaf, 0x39, 0xf2, 0x5d, 0x3d, 0xcb, 0x50, 0x49, 0x77, 0x8d, 0xec, 0xef, 0x17, 0x60, 0xac, - 0x01, 0x80, 0x06, 0xe6, 0x1c, 0x85, 0x95, 0xe1, 0x1c, 0x85, 0x3a, 0xa1, 0x69, 0xb3, 0x14, 0xe8, - 0x8b, 0x50, 0x0c, 0xbb, 0x4e, 0x2c, 0x75, 0x74, 0x5e, 0xea, 0x68, 0x9f, 0x2e, 0x3e, 0x32, 0xfb, - 0x14, 0x6c, 0x05, 0x73, 0x6c, 0xd3, 0xd9, 0xe6, 0x8f, 0x09, 0x40, 0x5f, 0xe3, 0x6d, 0x59, 0x4c, - 0xe2, 0x41, 0x2f, 0x11, 0xc9, 0xfc, 0x5e, 0x56, 0x9a, 0xe5, 0x54, 0x75, 0x7f, 0x96, 0x3f, 0x63, - 0x83, 0x23, 0xfa, 0x4d, 0xa8, 0xc6, 0x89, 0x13, 0x25, 0x4f, 0xd8, 0x30, 0x52, 0xea, 0x6b, 0x4a, - 0x22, 0x58, 0xd3, 0x43, 0x6f, 0x03, 0xb4, 0x3d, 0xdf, 0x8b, 0xbb, 0x8c, 0x7a, 0xf9, 0xc9, 0x82, - 0xeb, 0x55, 0x45, 0x01, 0x1b, 0xd4, 0xec, 0x0f, 0x73, 0xb0, 0x64, 0xcc, 0x7e, 0xcd, 0x61, 0xf0, - 0x63, 0xb3, 0x6a, 0xb9, 0x39, 0x67, 0xd5, 0x5e, 0x86, 0x4a, 0x18, 0xf4, 0x3c, 0xd7, 0x53, 0x37, - 0x44, 0x2c, 0x0c, 0xec, 0x8b, 0x35, 0xac, 0xa0, 0x28, 0x81, 0xea, 0xbd, 0xfb, 0x09, 0xf3, 0x70, - 0xf2, 0x86, 0x68, 0x91, 0x8b, 0x10, 0xe9, 0x2d, 0xb5, 0x92, 0xe5, 0x4a, 0x8c, 0x35, 0x23, 0x1a, - 0xca, 0x3a, 0x51, 0x30, 0x08, 0x79, 0xdb, 0x51, 0x34, 0x67, 0xd8, 0x5c, 0x58, 0x8c, 0x05, 0xc4, - 0xfe, 0x41, 0x1e, 0xc0, 0x08, 0x9f, 0x17, 0xa0, 0x10, 0x91, 0x30, 0x18, 0xd7, 0x15, 0xc5, 0xc0, - 0x0c, 0x92, 0x0a, 0x55, 0xb9, 0x13, 0x85, 0xaa, 0xfc, 0xb1, 0xc5, 0xef, 0xaf, 0xc3, 0x4a, 0x1c, - 0x77, 0xf7, 0x23, 0x6f, 0xe8, 0x24, 0xe4, 0x26, 0x19, 0x89, 0x29, 0x94, 0xb3, 0xe2, 0x95, 0x95, - 0x66, 0xf3, 0xba, 0x06, 0xe2, 0x34, 0xee, 0xd4, 0xbe, 0x41, 0xf1, 0x67, 0xd7, 0x37, 0x40, 0x4d, - 0x38, 0xeb, 0xf9, 0x31, 0x71, 0x07, 0x91, 0xb8, 0x8a, 0xb8, 0x1e, 0xc4, 0x09, 0xdd, 0x54, 0x89, - 0x05, 0x8f, 0x97, 0x04, 0xa1, 0xb3, 0x3b, 0xd3, 0x90, 0xf0, 0xf4, 0x77, 0xd9, 0x18, 0xac, 0x3e, - 0xae, 0xff, 0x5f, 0x63, 0xb0, 0x5a, 0xee, 0x19, 0x95, 0xed, 0x87, 0x6c, 0x73, 0xbc, 0x22, 0xdc, - 0x74, 0xe5, 0x68, 0xda, 0x31, 0xdf, 0xee, 0x10, 0x4a, 0xec, 0x12, 0x5a, 0x4a, 0xb8, 0x97, 0x41, - 0x2f, 0x91, 0x33, 0x67, 0xf1, 0x5b, 0xa7, 0xcd, 0xec, 0x31, 0xc6, 0x82, 0x9b, 0xdd, 0x87, 0x5a, - 0x1a, 0x7d, 0x9b, 0x50, 0x1f, 0x34, 0xa7, 0xd4, 0x1b, 0x50, 0x75, 0xd8, 0x5b, 0xbb, 0x03, 0x67, - 0x7c, 0xc6, 0x6d, 0x53, 0x02, 0xb0, 0xc6, 0xb1, 0xff, 0xc2, 0x82, 0xe7, 0xa6, 0x88, 0x97, 0x61, - 0x62, 0xc3, 0x1a, 0xa1, 0xf9, 0xc7, 0x8d, 0x00, 0xb6, 0x48, 0xdb, 0x91, 0xb1, 0xc8, 0x88, 0x5c, - 0xdb, 0x7c, 0x19, 0x4b, 0xb8, 0xfd, 0xef, 0x16, 0x9c, 0x4e, 0xcb, 0x1a, 0xa3, 0x1b, 0x80, 0xf8, - 0x66, 0xb6, 0xbd, 0xd8, 0x0d, 0x86, 0x24, 0x1a, 0xd1, 0x9d, 0x73, 0xa9, 0xd7, 0x05, 0x25, 0xb4, - 0x39, 0x81, 0x81, 0xa7, 0xbc, 0x85, 0xbe, 0xcd, 0x9a, 0x05, 0x52, 0xdb, 0xf2, 0xe0, 0x9b, 0x99, - 0x1d, 0xbc, 0x3e, 0x49, 0x33, 0x08, 0x28, 0x7e, 0xd8, 0x64, 0x6e, 0xff, 0x55, 0x0e, 0x96, 0xe5, - 0xeb, 0xdb, 0x5e, 0xbb, 0x4d, 0xf5, 0xcd, 0x7c, 0xab, 0xd8, 0x9c, 0xd2, 0x37, 0x73, 0xbc, 0x98, - 0xc3, 0xa8, 0xbe, 0x0f, 0x3d, 0xbf, 0x35, 0x9e, 0xe0, 0xdd, 0xf4, 0xfc, 0x16, 0x66, 0x90, 0xf4, - 0x14, 0x64, 0xfe, 0xf8, 0x29, 0x48, 0x65, 0x09, 0x85, 0xc7, 0x85, 0x39, 0x3e, 0xb7, 0xa7, 0x9d, - 0xa3, 0x11, 0xe6, 0x0e, 0x34, 0x08, 0x9b, 0x78, 0x54, 0x92, 0x9e, 0x37, 0x24, 0xfc, 0xa5, 0x52, - 0x5a, 0x92, 0x5d, 0x09, 0xc0, 0x1a, 0x87, 0x4a, 0xd2, 0xf2, 0xda, 0x6d, 0x51, 0x9b, 0x28, 0x49, - 0xa8, 0x76, 0x30, 0x83, 0xd8, 0xff, 0x61, 0xc1, 0xa7, 0x67, 0xde, 0xd3, 0x66, 0xa5, 0x41, 0xa9, - 0x90, 0xfc, 0xe3, 0xbe, 0x42, 0xad, 0xe3, 0xc2, 0x1c, 0x3a, 0x7e, 0x0d, 0x96, 0xef, 0xc5, 0x81, - 0xbf, 0x1f, 0x78, 0x3e, 0x1b, 0xb3, 0x29, 0xea, 0x4b, 0x92, 0x1b, 0xcd, 0xdb, 0x7b, 0x72, 0x1d, - 0xa7, 0xb0, 0xec, 0x1f, 0x15, 0xe1, 0x05, 0x75, 0x4d, 0x41, 0x92, 0xfb, 0x41, 0x74, 0xe8, 0xf9, - 0x1d, 0x56, 0x94, 0x7d, 0xcf, 0x82, 0x65, 0xae, 0x6b, 0x31, 0x3e, 0xc2, 0x2f, 0x44, 0xdc, 0x2c, - 0x2e, 0x44, 0x52, 0x9c, 0xea, 0x07, 0x06, 0x97, 0xb1, 0xd1, 0x11, 0x13, 0x84, 0x53, 0xe2, 0xa0, - 0xf7, 0x00, 0xe4, 0xa8, 0x67, 0x3b, 0x8b, 0x69, 0x57, 0x29, 0x1c, 0x26, 0x6d, 0x7d, 0x69, 0x79, - 0xa0, 0x38, 0x60, 0x83, 0x1b, 0xfa, 0x96, 0x05, 0xa5, 0x1e, 0xd7, 0x4a, 0x9e, 0x31, 0xfe, 0xad, - 0xec, 0xb5, 0x62, 0xea, 0x43, 0x79, 0x7a, 0xa1, 0x09, 0xc1, 0x1c, 0x61, 0x28, 0x7b, 0x7e, 0x27, - 0x22, 0xb1, 0x4c, 0xdd, 0x3e, 0x6b, 0xc4, 0xd7, 0xba, 0x1b, 0x44, 0x84, 0x45, 0xd3, 0xc0, 0x69, - 0x35, 0x9c, 0x9e, 0xe3, 0xbb, 0x24, 0xda, 0xe1, 0xe8, 0xda, 0x45, 0x8a, 0x05, 0x2c, 0x09, 0x4d, - 0xdc, 0xb6, 0x15, 0xe7, 0xb9, 0x6d, 0x5b, 0x7f, 0x1d, 0xd6, 0x26, 0x8e, 0xf1, 0x24, 0x83, 0x3c, - 0xeb, 0x5f, 0x82, 0xa5, 0x27, 0x9d, 0x01, 0xfa, 0x49, 0x51, 0xfb, 0xb9, 0xbd, 0xa0, 0xc5, 0xae, - 0xbb, 0x22, 0x7d, 0x9a, 0x22, 0xf5, 0xc8, 0xca, 0x36, 0x8c, 0xd9, 0x41, 0xb5, 0x88, 0x4d, 0x7e, - 0xd4, 0x32, 0x43, 0x27, 0xa2, 0x75, 0xf3, 0x53, 0xb4, 0xcc, 0x7d, 0xc5, 0x01, 0x1b, 0xdc, 0x10, - 0x11, 0xa3, 0x21, 0xf9, 0x85, 0x33, 0x79, 0xd9, 0x4a, 0x99, 0x36, 0x1e, 0x42, 0x33, 0xda, 0x55, - 0x3f, 0x65, 0xaf, 0xa2, 0x0c, 0x7c, 0x23, 0xf3, 0x0f, 0x81, 0xdf, 0xad, 0xa7, 0xd7, 0xf0, 0x18, - 0x73, 0xb4, 0x09, 0xa7, 0xe5, 0x09, 0xbc, 0x49, 0x22, 0x36, 0x26, 0xce, 0x63, 0x88, 0x4a, 0x8a, - 0x71, 0x1a, 0x8c, 0xc7, 0xf1, 0x8d, 0xfb, 0xe2, 0xd2, 0xcc, 0x91, 0xba, 0x43, 0x35, 0x1a, 0x52, - 0xce, 0x76, 0x34, 0x04, 0x26, 0xc7, 0x42, 0xec, 0x1f, 0x5a, 0x70, 0x46, 0x4a, 0x7d, 0x7b, 0x48, - 0xa2, 0xc8, 0x6b, 0xb1, 0xb8, 0xc0, 0xc1, 0x3a, 0x47, 0x51, 0x71, 0xe1, 0xba, 0x04, 0x60, 0x8d, - 0x83, 0xae, 0x4d, 0x1b, 0x65, 0xe2, 0x91, 0xe9, 0x64, 0x43, 0x47, 0xaf, 0x40, 0x99, 0x27, 0x3c, - 0xf1, 0x78, 0x7f, 0x40, 0x24, 0x52, 0x58, 0xc2, 0xed, 0xff, 0xb2, 0xc0, 0xfc, 0x3a, 0xe6, 0x8b, - 0x9a, 0xaf, 0x40, 0x79, 0x28, 0x8e, 0x6e, 0xac, 0xd9, 0x2b, 0x8f, 0x4c, 0xc2, 0x55, 0x80, 0xcd, - 0xcf, 0x97, 0xa2, 0x14, 0x4e, 0x90, 0xa2, 0x14, 0x67, 0x46, 0xe4, 0x97, 0x20, 0x3f, 0xf0, 0x5a, - 0x22, 0xcb, 0xd0, 0xed, 0xdb, 0x9d, 0x6d, 0x4c, 0xd7, 0xed, 0x7f, 0xcd, 0xeb, 0x0a, 0x41, 0xb4, - 0x29, 0x7e, 0x2e, 0xb6, 0xfd, 0x9a, 0xea, 0xd5, 0xf3, 0x9d, 0xbf, 0x98, 0xee, 0xd5, 0x3f, 0x7a, - 0x78, 0x1e, 0xf8, 0x76, 0x59, 0xa7, 0x71, 0x4a, 0xe7, 0xbe, 0x7c, 0x4c, 0x33, 0xe9, 0x32, 0x54, - 0xba, 0x41, 0x70, 0xc8, 0x06, 0x57, 0x2a, 0x29, 0x16, 0x95, 0xeb, 0x62, 0xfd, 0x91, 0xf1, 0x1b, - 0x2b, 0x6c, 0xb4, 0x09, 0x55, 0xfa, 0x9b, 0x75, 0xb1, 0xc4, 0xcc, 0xcb, 0x45, 0xf5, 0x2d, 0x48, - 0xc0, 0x94, 0x86, 0x97, 0x7e, 0x8b, 0x2a, 0x8c, 0xcd, 0xfd, 0x31, 0x12, 0x90, 0x56, 0x58, 0x53, - 0x02, 0xb0, 0xc6, 0xb1, 0x3f, 0x31, 0x8e, 0x59, 0xdc, 0x66, 0xfc, 0x5c, 0x1c, 0xf3, 0xe5, 0xb1, - 0x63, 0xbe, 0x30, 0x71, 0xcc, 0xab, 0x7a, 0x6c, 0x2e, 0x75, 0xd4, 0xcf, 0xd2, 0x27, 0xd2, 0x8d, - 0xd0, 0xc3, 0x63, 0x86, 0x62, 0x74, 0xb9, 0xe9, 0x69, 0x63, 0x06, 0xe1, 0x91, 0xe0, 0xdd, 0x81, - 0x17, 0x91, 0x78, 0x3f, 0x1a, 0xf8, 0x9e, 0xdf, 0x61, 0xa6, 0x51, 0x31, 0x23, 0x41, 0x0a, 0x8c, - 0xc7, 0xf1, 0xed, 0xbf, 0xcc, 0xd1, 0x22, 0x31, 0x35, 0x46, 0x87, 0x3e, 0x0f, 0x95, 0x48, 0xfe, - 0x01, 0x69, 0xac, 0xb7, 0xa4, 0xfe, 0x7a, 0xa4, 0x30, 0xd0, 0x57, 0x01, 0x5a, 0x24, 0xec, 0x05, - 0x23, 0xd6, 0x43, 0x2c, 0x9c, 0xb8, 0x87, 0xa8, 0xa2, 0xfc, 0xb6, 0xa2, 0x82, 0x0d, 0x8a, 0x68, - 0x1d, 0x72, 0x5e, 0x8b, 0x9d, 0x66, 0xbe, 0x01, 0x02, 0x37, 0xb7, 0xb3, 0x8d, 0x73, 0x5e, 0xcb, - 0xb8, 0x25, 0x2f, 0x3d, 0xbb, 0x5b, 0x72, 0xfb, 0xef, 0x58, 0xb0, 0xe2, 0xdb, 0xbf, 0x25, 0x3b, - 0x34, 0x9f, 0x81, 0x92, 0x33, 0x48, 0xba, 0xc1, 0xc4, 0xac, 0xcf, 0x26, 0x5b, 0xc5, 0x02, 0x8a, - 0x76, 0xa1, 0xd0, 0xa2, 0x15, 0x5c, 0xee, 0xc4, 0x8a, 0xd2, 0x15, 0x1c, 0x2d, 0xf4, 0x18, 0x15, - 0xf4, 0x22, 0x14, 0x12, 0xa7, 0x23, 0xfb, 0x9e, 0xac, 0x4f, 0xcf, 0xc6, 0xe7, 0xd9, 0xaa, 0xe9, - 0x99, 0x0a, 0xc7, 0xdc, 0x29, 0xfe, 0xa0, 0x00, 0x2b, 0xa9, 0xd6, 0x74, 0xca, 0x0a, 0xac, 0x63, - 0xad, 0xe0, 0x22, 0x14, 0xc3, 0x68, 0xe0, 0xf3, 0x7d, 0x55, 0xb4, 0x63, 0xa0, 0x76, 0x46, 0x30, - 0x87, 0x51, 0x1d, 0xb5, 0xa2, 0x11, 0x1e, 0xf8, 0xe2, 0xe6, 0x46, 0xe9, 0x68, 0x9b, 0xad, 0x62, - 0x01, 0x45, 0xef, 0xc3, 0x72, 0xcc, 0x3e, 0xc0, 0xc8, 0x49, 0x48, 0x47, 0x0e, 0x43, 0x5f, 0x5b, - 0x78, 0x0c, 0x96, 0x93, 0xe3, 0xf9, 0xbd, 0xb9, 0x82, 0x53, 0xec, 0xd0, 0x37, 0x2d, 0x73, 0xf4, - 0x97, 0x0f, 0x1e, 0xef, 0x67, 0xd8, 0xf2, 0xe7, 0xd6, 0xf5, 0xf8, 0x09, 0xe0, 0x50, 0x59, 0x76, - 0xf9, 0x29, 0x58, 0x36, 0x4c, 0x99, 0xfd, 0xf8, 0x1c, 0x54, 0xfb, 0x8e, 0xef, 0xb5, 0x49, 0x9c, - 0xc4, 0xb5, 0x0a, 0xb3, 0x27, 0xf6, 0x9f, 0xb3, 0x5b, 0x72, 0x11, 0x6b, 0xb8, 0xfd, 0x0d, 0x0b, - 0xce, 0x4e, 0xdd, 0xd6, 0x33, 0xeb, 0x1a, 0x50, 0xcf, 0xf5, 0xdc, 0x94, 0xcb, 0x14, 0x34, 0x7c, - 0x3a, 0x73, 0xdb, 0xe2, 0xaa, 0x66, 0x65, 0xe6, 0x89, 0x9d, 0xcc, 0x6b, 0x6a, 0xcf, 0x95, 0x7f, - 0x86, 0x9e, 0xeb, 0x0f, 0x2d, 0x30, 0xfe, 0x07, 0x80, 0x7e, 0x07, 0xaa, 0xce, 0x20, 0x09, 0xfa, - 0x4e, 0x42, 0x5a, 0xa2, 0x72, 0xdc, 0xcb, 0xe4, 0x1f, 0x07, 0x9b, 0x92, 0x2a, 0xd7, 0x97, 0x7a, - 0xc4, 0x9a, 0x9f, 0xfd, 0x65, 0x7e, 0x7c, 0x63, 0x2f, 0x68, 0x47, 0x62, 0xcd, 0x76, 0x24, 0xf6, - 0x7f, 0x8a, 0x7d, 0x88, 0xac, 0xe4, 0xf2, 0xd8, 0x8c, 0xc5, 0xfc, 0x01, 0x7d, 0x04, 0xe0, 0xaa, - 0xa1, 0xab, 0x0c, 0xc6, 0xed, 0xf5, 0x04, 0x97, 0x39, 0x0c, 0x2e, 0xd7, 0xb0, 0xc1, 0x2c, 0x65, - 0x2f, 0xf9, 0xe3, 0xec, 0xc5, 0xfe, 0x37, 0x0b, 0x52, 0x2e, 0x0b, 0xf5, 0xa1, 0x48, 0x25, 0x18, - 0x65, 0x30, 0x1f, 0x66, 0xd2, 0xa5, 0xb6, 0x34, 0x6a, 0x54, 0xa9, 0xc6, 0xd9, 0x4f, 0xcc, 0xb9, - 0x20, 0x4f, 0x24, 0x23, 0x5c, 0x45, 0x37, 0x33, 0xe2, 0x46, 0x73, 0x19, 0xf1, 0xaf, 0x62, 0x95, - 0xd5, 0xd8, 0x97, 0x61, 0x6d, 0x42, 0x22, 0x6a, 0x16, 0x6c, 0xe4, 0x64, 0xdc, 0x2c, 0xd8, 0x50, - 0x0a, 0xe6, 0x30, 0xfb, 0x43, 0x0b, 0xce, 0x8c, 0x93, 0x47, 0x7f, 0x66, 0xc1, 0x5a, 0x3c, 0x4e, - 0xef, 0xa9, 0x68, 0x4d, 0xd5, 0x98, 0x13, 0x20, 0x3c, 0x29, 0x01, 0x3d, 0xd1, 0xf1, 0x01, 0x4e, - 0x6a, 0x13, 0xf2, 0xc2, 0x49, 0x6c, 0x54, 0xcf, 0x5e, 0x88, 0x75, 0xac, 0x30, 0xd0, 0x25, 0x00, - 0x3e, 0x40, 0xbc, 0xa7, 0x6f, 0x01, 0x95, 0xd5, 0x35, 0x15, 0x04, 0x1b, 0x58, 0xa9, 0x99, 0x99, - 0xfc, 0xbc, 0x33, 0x33, 0x85, 0xc7, 0xcc, 0xcc, 0xe8, 0x41, 0x9d, 0xe2, 0xac, 0x41, 0x9d, 0x46, - 0xfd, 0xa3, 0x4f, 0xce, 0x9d, 0xfa, 0xf1, 0x27, 0xe7, 0x4e, 0x7d, 0xfc, 0xc9, 0xb9, 0x53, 0xdf, - 0x38, 0x3a, 0x67, 0x7d, 0x74, 0x74, 0xce, 0xfa, 0xf1, 0xd1, 0x39, 0xeb, 0xe3, 0xa3, 0x73, 0xd6, - 0xbf, 0x1c, 0x9d, 0xb3, 0xfe, 0xe4, 0xa7, 0xe7, 0x4e, 0xbd, 0x5d, 0x91, 0xaa, 0xfd, 0xbf, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x0d, 0x1f, 0xa3, 0x91, 0x2f, 0x49, 0x00, 0x00, + proto.RegisterFile("github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto", fileDescriptor_generated_2473a92fb8cd7948) +} + +var fileDescriptor_generated_2473a92fb8cd7948 = []byte{ + // 4359 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x3c, 0x4b, 0x8c, 0x1c, 0xc7, + 0x75, 0xec, 0xf9, 0xcf, 0xdb, 0x0f, 0xb9, 0x25, 0x51, 0x1e, 0x2f, 0xa4, 0x5d, 0xa2, 0x99, 0xd8, + 0x52, 0x64, 0xcf, 0x46, 0x84, 0x9c, 0xd0, 0x0e, 0x10, 0x61, 0x67, 0x77, 0x49, 0x2e, 0xb9, 0x5c, + 0xae, 0x6a, 0x96, 0x12, 0xa0, 0x38, 0x8e, 0x9a, 0x3d, 0x35, 0x33, 0xcd, 0x9d, 0xe9, 0x6e, 0x75, + 0xf7, 0x0c, 0x39, 0x4a, 0xe4, 0x4f, 0x02, 0x03, 0x89, 0x1d, 0x19, 0x01, 0x82, 0x9c, 0x0c, 0x1f, + 0xe2, 0x5b, 0x84, 0x5c, 0x92, 0x43, 0x7c, 0xf7, 0x21, 0xd1, 0xd1, 0x09, 0x1c, 0x40, 0x50, 0x02, + 0x22, 0x5a, 0xe7, 0x10, 0x24, 0x87, 0x24, 0x08, 0x72, 0x21, 0x72, 0x08, 0xea, 0xd7, 0x55, 0xdd, + 0x33, 0xc3, 0x9d, 0xe5, 0x34, 0x69, 0x44, 0xb9, 0x75, 0xd7, 0x7b, 0xfd, 0xde, 0xab, 0x57, 0xaf, + 0xea, 0x7d, 0xea, 0xcd, 0xc0, 0x6e, 0xc7, 0x89, 0xba, 0x83, 0x3b, 0x75, 0xdb, 0xeb, 0x6f, 0x58, + 0x41, 0xc7, 0xf3, 0x03, 0xef, 0x2e, 0x7b, 0xf8, 0xa2, 0xdd, 0xda, 0xf0, 0x8f, 0x3a, 0x1b, 0x96, + 0xef, 0x84, 0x1b, 0x96, 0xef, 0xf7, 0x1c, 0xdb, 0x8a, 0x1c, 0xcf, 0xdd, 0x18, 0xbe, 0x62, 0xf5, + 0xfc, 0xae, 0xf5, 0xca, 0x46, 0x87, 0xb8, 0x24, 0xb0, 0x22, 0xd2, 0xaa, 0xfb, 0x81, 0x17, 0x79, + 0xe8, 0xcb, 0x8a, 0x54, 0x5d, 0x92, 0x62, 0x0f, 0xbf, 0x65, 0xb7, 0xea, 0xfe, 0x51, 0xa7, 0x4e, + 0x49, 0xd5, 0x35, 0x52, 0x75, 0x49, 0x6a, 0xf5, 0x8b, 0x9a, 0x14, 0x1d, 0xaf, 0xe3, 0x6d, 0x30, + 0x8a, 0x77, 0x06, 0x6d, 0xf6, 0xc6, 0x5e, 0xd8, 0x13, 0xe7, 0xb4, 0x6a, 0x1e, 0x5d, 0x0e, 0xeb, + 0x8e, 0x47, 0x65, 0xdb, 0xb0, 0xbd, 0x80, 0x6c, 0x0c, 0xc7, 0xa4, 0x59, 0x7d, 0x55, 0xe1, 0xf4, + 0x2d, 0xbb, 0xeb, 0xb8, 0x24, 0x18, 0xa9, 0x09, 0xf5, 0x49, 0x64, 0x4d, 0xfa, 0x6a, 0x63, 0xda, + 0x57, 0xc1, 0xc0, 0x8d, 0x9c, 0x3e, 0x19, 0xfb, 0xe0, 0x57, 0x4e, 0xfa, 0x20, 0xb4, 0xbb, 0xa4, + 0x6f, 0xa5, 0xbf, 0x33, 0xdf, 0x81, 0xa5, 0xcd, 0x37, 0x9b, 0x9b, 0x83, 0xa8, 0xbb, 0xe5, 0xb9, + 0x6d, 0xa7, 0x83, 0xbe, 0x04, 0x0b, 0x76, 0x6f, 0x10, 0x46, 0x24, 0xd8, 0xb7, 0xfa, 0xa4, 0x66, + 0x5c, 0x30, 0x5e, 0xac, 0x36, 0x9e, 0xf9, 0xf0, 0xc1, 0xfa, 0x99, 0xe3, 0x07, 0xeb, 0x0b, 0x5b, + 0x0a, 0x84, 0x75, 0x3c, 0xf4, 0x12, 0x94, 0x03, 0xaf, 0x47, 0x36, 0xf1, 0x7e, 0x2d, 0xc7, 0x3e, + 0x39, 0x2b, 0x3e, 0x29, 0x63, 0x3e, 0x8c, 0x25, 0xdc, 0xfc, 0x07, 0x03, 0x60, 0xd3, 0xf7, 0x0f, + 0x02, 0xef, 0x2e, 0xb1, 0x23, 0xf4, 0x36, 0x54, 0xa8, 0x16, 0x5a, 0x56, 0x64, 0x31, 0x6e, 0x0b, + 0x97, 0x7e, 0xb9, 0xce, 0x27, 0x53, 0xd7, 0x27, 0xa3, 0x56, 0x8e, 0x62, 0xd7, 0x87, 0xaf, 0xd4, + 0x6f, 0xdd, 0xa1, 0xdf, 0xdf, 0x24, 0x91, 0xd5, 0x40, 0x82, 0x19, 0xa8, 0x31, 0x1c, 0x53, 0x45, + 0x47, 0x50, 0x08, 0x7d, 0x62, 0x33, 0xc1, 0x16, 0x2e, 0xed, 0xd6, 0x1f, 0xdb, 0x3e, 0xea, 0x4a, + 0xec, 0xa6, 0x4f, 0xec, 0xc6, 0xa2, 0x60, 0x5b, 0xa0, 0x6f, 0x98, 0x31, 0x31, 0x3f, 0x36, 0x60, + 0x59, 0xa1, 0xed, 0x39, 0x61, 0x84, 0xbe, 0x3a, 0x36, 0xc3, 0xfa, 0x6c, 0x33, 0xa4, 0x5f, 0xb3, + 0xf9, 0x9d, 0x13, 0x8c, 0x2a, 0x72, 0x44, 0x9b, 0xdd, 0x5d, 0x28, 0x3a, 0x11, 0xe9, 0x87, 0xb5, + 0xdc, 0x85, 0xfc, 0x8b, 0x0b, 0x97, 0x76, 0x32, 0x99, 0x5e, 0x63, 0x49, 0x70, 0x2c, 0xee, 0x52, + 0xda, 0x98, 0xb3, 0x30, 0xbf, 0x5f, 0xd4, 0x27, 0x47, 0x67, 0x8d, 0x5e, 0x81, 0x85, 0xd0, 0x1b, + 0x04, 0x36, 0xc1, 0xc4, 0xf7, 0xc2, 0x9a, 0x71, 0x21, 0x4f, 0x17, 0x9f, 0xda, 0x4a, 0x53, 0x0d, + 0x63, 0x1d, 0x07, 0x7d, 0xd7, 0x80, 0xc5, 0x16, 0x09, 0x23, 0xc7, 0x65, 0xfc, 0xa5, 0xe4, 0xaf, + 0xcf, 0x27, 0xb9, 0x1c, 0xdc, 0x56, 0x94, 0x1b, 0xcf, 0x8a, 0x59, 0x2c, 0x6a, 0x83, 0x21, 0x4e, + 0x30, 0xa7, 0x06, 0xdf, 0x22, 0xa1, 0x1d, 0x38, 0x3e, 0x7d, 0xaf, 0xe5, 0x93, 0x06, 0xbf, 0xad, + 0x40, 0x58, 0xc7, 0x43, 0x47, 0x50, 0xa4, 0x06, 0x1d, 0xd6, 0x0a, 0x4c, 0xf8, 0x2b, 0x73, 0x08, + 0x2f, 0xd4, 0x49, 0x37, 0x8a, 0xd2, 0x3b, 0x7d, 0x0b, 0x31, 0xe7, 0x81, 0xde, 0x37, 0xa0, 0x26, + 0x76, 0x1b, 0x26, 0x5c, 0x95, 0x6f, 0x76, 0x9d, 0x88, 0xf4, 0x9c, 0x30, 0xaa, 0x15, 0x99, 0x00, + 0x1b, 0xb3, 0x99, 0xd4, 0xd5, 0xc0, 0x1b, 0xf8, 0x37, 0x1c, 0xb7, 0xd5, 0xb8, 0x20, 0x38, 0xd5, + 0xb6, 0xa6, 0x10, 0xc6, 0x53, 0x59, 0xa2, 0x3f, 0x36, 0x60, 0xd5, 0xb5, 0xfa, 0x24, 0xf4, 0x2d, + 0xba, 0xa8, 0x1c, 0xdc, 0xe8, 0x59, 0xf6, 0x11, 0x93, 0xa8, 0xf4, 0x78, 0x12, 0x99, 0x42, 0xa2, + 0xd5, 0xfd, 0xa9, 0xa4, 0xf1, 0x23, 0xd8, 0x9a, 0x7f, 0x9d, 0x87, 0x05, 0xcd, 0x10, 0x9e, 0xc2, + 0xc9, 0xd2, 0x4b, 0x9c, 0x2c, 0xd7, 0xb3, 0x31, 0xe0, 0x69, 0x47, 0x0b, 0x8a, 0xa0, 0x14, 0x46, + 0x56, 0x34, 0x08, 0x99, 0x91, 0x2e, 0x5c, 0xda, 0xcb, 0x88, 0x1f, 0xa3, 0xd9, 0x58, 0x16, 0x1c, + 0x4b, 0xfc, 0x1d, 0x0b, 0x5e, 0xe8, 0x1d, 0xa8, 0x7a, 0x3e, 0xf5, 0x19, 0x74, 0x77, 0x14, 0x18, + 0xe3, 0xed, 0x39, 0x18, 0xdf, 0x92, 0xb4, 0x1a, 0x4b, 0xc7, 0x0f, 0xd6, 0xab, 0xf1, 0x2b, 0x56, + 0x5c, 0x4c, 0x1b, 0x9e, 0xd5, 0xe4, 0xdb, 0xf2, 0xdc, 0x96, 0xc3, 0x16, 0xf4, 0x02, 0x14, 0xa2, + 0x91, 0x2f, 0x9d, 0x52, 0xac, 0xa2, 0xc3, 0x91, 0x4f, 0x30, 0x83, 0x50, 0x37, 0xd4, 0x27, 0x61, + 0x68, 0x75, 0x48, 0xda, 0x0d, 0xdd, 0xe4, 0xc3, 0x58, 0xc2, 0xcd, 0x77, 0xe0, 0xb9, 0xc9, 0xa7, + 0x06, 0xfa, 0x1c, 0x94, 0x42, 0x12, 0x0c, 0x49, 0x20, 0x18, 0x29, 0xcd, 0xb0, 0x51, 0x2c, 0xa0, + 0x68, 0x03, 0xaa, 0xb1, 0x35, 0x0a, 0x76, 0x2b, 0x02, 0xb5, 0xaa, 0x4c, 0x58, 0xe1, 0x98, 0xff, + 0x68, 0xc0, 0x59, 0x8d, 0xe7, 0x53, 0x70, 0x0e, 0x47, 0x49, 0xe7, 0x70, 0x25, 0x1b, 0x8b, 0x99, + 0xe2, 0x1d, 0xbe, 0x57, 0x82, 0x15, 0xdd, 0xae, 0xd8, 0xf6, 0x64, 0x91, 0x01, 0xf1, 0xbd, 0xdb, + 0x78, 0x4f, 0xa8, 0x53, 0x45, 0x06, 0x7c, 0x18, 0x4b, 0x38, 0x5d, 0x5f, 0xdf, 0x8a, 0xba, 0x42, + 0x97, 0xf1, 0xfa, 0x1e, 0x58, 0x51, 0x17, 0x33, 0x08, 0xfa, 0x75, 0x58, 0x8e, 0xac, 0xa0, 0x43, + 0x22, 0x4c, 0x86, 0x4e, 0x28, 0x2d, 0xb2, 0xda, 0x78, 0x4e, 0xe0, 0x2e, 0x1f, 0x26, 0xa0, 0x38, + 0x85, 0x8d, 0x5c, 0x28, 0x74, 0x49, 0xaf, 0x5f, 0x2b, 0x33, 0x4d, 0x1f, 0x64, 0xb4, 0x81, 0xd8, + 0x44, 0xaf, 0x91, 0x5e, 0xbf, 0x51, 0xa1, 0xf2, 0xd2, 0x27, 0xcc, 0xf8, 0xa0, 0xdf, 0x35, 0xa0, + 0x7a, 0x34, 0x08, 0x23, 0xaf, 0xef, 0xbc, 0x4b, 0x6a, 0x15, 0xc6, 0xf5, 0x76, 0x96, 0x5c, 0x6f, + 0x48, 0xe2, 0x7c, 0x3b, 0xc5, 0xaf, 0x58, 0xb1, 0x45, 0xef, 0x42, 0xf9, 0x28, 0xf4, 0x5c, 0x97, + 0x44, 0xb5, 0x2a, 0x93, 0xa0, 0x99, 0xa9, 0x04, 0x9c, 0x74, 0x63, 0x81, 0x2e, 0xa9, 0x78, 0xc1, + 0x92, 0x21, 0x53, 0x40, 0xcb, 0x09, 0x88, 0x1d, 0x79, 0xc1, 0xa8, 0x06, 0xd9, 0x2b, 0x60, 0x5b, + 0x12, 0xe7, 0x0a, 0x88, 0x5f, 0xb1, 0x62, 0x8b, 0x86, 0x50, 0xf2, 0x7b, 0x83, 0x8e, 0xe3, 0xd6, + 0x16, 0x98, 0x00, 0x38, 0x4b, 0x01, 0x0e, 0x18, 0xe5, 0x06, 0xd0, 0x03, 0x82, 0x3f, 0x63, 0xc1, + 0xcd, 0xfc, 0x1b, 0x03, 0x56, 0xa7, 0x0b, 0xcc, 0x77, 0x86, 0x3d, 0x08, 0x42, 0x7e, 0xa2, 0x55, + 0xf4, 0x9d, 0xc1, 0x86, 0xb1, 0x84, 0xa3, 0xaf, 0x43, 0xf9, 0xae, 0x58, 0xc2, 0x5c, 0xf6, 0x4b, + 0x78, 0x5d, 0x2c, 0x61, 0xcc, 0xff, 0xba, 0x5c, 0x46, 0xc1, 0xd4, 0xfc, 0x1f, 0x03, 0xce, 0x4f, + 0xb4, 0x78, 0x54, 0x07, 0x18, 0x5a, 0xbd, 0x01, 0xb9, 0xe2, 0xd0, 0x60, 0x88, 0x87, 0x7f, 0xcb, + 0xd4, 0x61, 0xbe, 0x11, 0x8f, 0x62, 0x0d, 0x03, 0xfd, 0x0e, 0x80, 0x6f, 0x05, 0x56, 0x9f, 0x44, + 0x24, 0x90, 0xc7, 0xd2, 0xb5, 0x39, 0x26, 0x43, 0x85, 0x38, 0x90, 0x04, 0x95, 0xbb, 0x8e, 0x87, + 0x42, 0xac, 0xf1, 0xa3, 0xc1, 0x5e, 0x40, 0x7a, 0xc4, 0x0a, 0x09, 0xcb, 0x6e, 0x52, 0xc1, 0x1e, + 0x56, 0x20, 0xac, 0xe3, 0x99, 0xff, 0x6d, 0x40, 0x6d, 0x9a, 0xd6, 0x90, 0x0f, 0x65, 0x72, 0x3f, + 0x7a, 0xc3, 0x0a, 0xf8, 0xf4, 0xe7, 0x0b, 0xc1, 0x05, 0xd1, 0x37, 0xac, 0x40, 0xad, 0xc6, 0x0e, + 0xa7, 0x8e, 0x25, 0x1b, 0xd4, 0x81, 0x42, 0xd4, 0xb3, 0xb2, 0x88, 0xf8, 0x35, 0x76, 0xca, 0x9d, + 0xee, 0x6d, 0x86, 0x98, 0x31, 0x30, 0xff, 0x6e, 0xd2, 0xbc, 0xc5, 0x1e, 0xa7, 0xba, 0x24, 0xee, + 0xd0, 0x09, 0x3c, 0xb7, 0x4f, 0xdc, 0x28, 0x9d, 0x29, 0xee, 0x28, 0x10, 0xd6, 0xf1, 0xd0, 0x37, + 0x26, 0x18, 0xc0, 0x8d, 0x39, 0xa6, 0x20, 0xc4, 0x99, 0xd9, 0x06, 0xcc, 0x8f, 0xf2, 0x13, 0x76, + 0x65, 0x7c, 0x70, 0xa2, 0x4b, 0x00, 0xd4, 0x63, 0x1f, 0x04, 0xa4, 0xed, 0xdc, 0x17, 0xb3, 0x8a, + 0x49, 0xee, 0xc7, 0x10, 0xac, 0x61, 0xa1, 0xf7, 0xa0, 0xea, 0xf4, 0xad, 0x0e, 0x39, 0xb4, 0x3a, + 0x72, 0x4a, 0xf3, 0x04, 0x67, 0xb1, 0x30, 0xbb, 0x82, 0xa8, 0x8a, 0x2b, 0xe4, 0x48, 0x88, 0x15, + 0x47, 0x64, 0x42, 0x89, 0xbd, 0xd0, 0xc0, 0x90, 0xee, 0x3f, 0x76, 0x16, 0x31, 0xcc, 0x10, 0x0b, + 0x08, 0xfa, 0x53, 0x03, 0x16, 0x6d, 0xaf, 0xdf, 0xf7, 0xdc, 0x3d, 0xeb, 0x0e, 0xe9, 0xc9, 0xbc, + 0xa5, 0xf3, 0x44, 0x9c, 0x51, 0x7d, 0x4b, 0xe3, 0xb4, 0xe3, 0x46, 0xc1, 0x48, 0xa5, 0x62, 0x3a, + 0x08, 0x27, 0x44, 0x5a, 0x7d, 0x0d, 0x56, 0xc6, 0x3e, 0x44, 0xe7, 0x20, 0x7f, 0x44, 0x46, 0x7c, + 0x21, 0x30, 0x7d, 0x44, 0xcf, 0x42, 0x91, 0x1d, 0x28, 0x3c, 0x4e, 0xc0, 0xfc, 0xe5, 0x2b, 0xb9, + 0xcb, 0x86, 0xf9, 0x7d, 0x03, 0x3e, 0x33, 0xe5, 0x80, 0xa6, 0xc1, 0x85, 0xab, 0x2a, 0x1a, 0xb1, + 0xb5, 0xb3, 0xcd, 0xce, 0x20, 0xe8, 0x6b, 0x90, 0x27, 0xee, 0x50, 0xac, 0xdf, 0xd6, 0x1c, 0x8a, + 0xd9, 0x71, 0x87, 0x7c, 0xd2, 0xe5, 0xe3, 0x07, 0xeb, 0xf9, 0x1d, 0x77, 0x88, 0x29, 0x61, 0xf3, + 0x47, 0xc5, 0x44, 0xf8, 0xd7, 0x94, 0x31, 0x3d, 0x93, 0x52, 0x04, 0x7f, 0x7b, 0x59, 0xae, 0x87, + 0x16, 0xb9, 0xf2, 0xf4, 0x5b, 0xf0, 0x42, 0xbf, 0x6f, 0xb0, 0xa4, 0x57, 0x46, 0xbc, 0xc2, 0xa7, + 0x3c, 0x81, 0x04, 0x5c, 0xcf, 0xa3, 0xe5, 0x20, 0xd6, 0x59, 0x53, 0x27, 0xe8, 0xf3, 0xfc, 0x57, + 0x9c, 0xc6, 0xf1, 0xb1, 0x27, 0xd3, 0x62, 0x09, 0x47, 0x03, 0x80, 0x70, 0xe4, 0xda, 0x07, 0x5e, + 0xcf, 0xb1, 0x47, 0x22, 0x15, 0x99, 0xe7, 0xf0, 0x6b, 0xc6, 0xc4, 0xb8, 0xc7, 0x52, 0xef, 0x58, + 0x63, 0x84, 0x7e, 0x60, 0xc0, 0x8a, 0xd3, 0x71, 0xbd, 0x80, 0x6c, 0x3b, 0xed, 0x36, 0x09, 0x88, + 0x6b, 0x93, 0x50, 0x64, 0xdd, 0x87, 0x73, 0xb0, 0x97, 0x09, 0xec, 0x6e, 0x9a, 0x76, 0xe3, 0xb3, + 0x42, 0x05, 0x2b, 0x63, 0x20, 0x3c, 0x2e, 0x09, 0xb2, 0xa0, 0xe0, 0xb8, 0x6d, 0x4f, 0x64, 0xdd, + 0xaf, 0xcd, 0x21, 0xd1, 0xae, 0xdb, 0xf6, 0xd4, 0xce, 0xa0, 0x6f, 0x98, 0x91, 0x36, 0xff, 0xab, + 0x92, 0x8c, 0xec, 0x79, 0x66, 0xf8, 0x2e, 0x54, 0x03, 0x31, 0x07, 0xe9, 0xfa, 0x76, 0x33, 0xd0, + 0x87, 0xc8, 0x47, 0xe3, 0x23, 0x4f, 0x8e, 0x87, 0x58, 0xb1, 0xa3, 0x2e, 0x90, 0x2e, 0x91, 0xb0, + 0xdc, 0x79, 0xad, 0x40, 0xb0, 0x54, 0x49, 0xf7, 0xc8, 0xa5, 0x49, 0xf7, 0xc8, 0xb5, 0x91, 0x07, + 0xa5, 0x2e, 0xb1, 0x7a, 0x51, 0x57, 0x24, 0xdd, 0x57, 0xe7, 0x8a, 0x55, 0x28, 0xa1, 0x74, 0xbe, + 0xcd, 0x47, 0xb1, 0x60, 0x83, 0x06, 0x50, 0xee, 0x3a, 0x21, 0x0b, 0x97, 0xf9, 0x11, 0x7d, 0x7d, + 0x2e, 0x9d, 0xf2, 0xc4, 0xe7, 0x1a, 0xa7, 0xa8, 0x36, 0x97, 0x18, 0xc0, 0x92, 0x17, 0xfa, 0x3d, + 0x03, 0xc0, 0x96, 0x99, 0xb6, 0x34, 0xef, 0x5b, 0xd9, 0x9c, 0x08, 0x71, 0x06, 0xaf, 0x1c, 0x69, + 0x3c, 0x14, 0x62, 0x8d, 0x2d, 0x7a, 0x1b, 0x16, 0x03, 0x62, 0x7b, 0xae, 0xed, 0xf4, 0x48, 0x6b, + 0x33, 0xaa, 0x95, 0x98, 0xce, 0x7f, 0x69, 0xb6, 0x8c, 0xf8, 0xd0, 0xe9, 0x93, 0xc6, 0x39, 0xea, + 0x63, 0xb0, 0x46, 0x03, 0x27, 0x28, 0xa2, 0x6f, 0x1b, 0xb0, 0x1c, 0x57, 0x1a, 0xe8, 0x52, 0x10, + 0x91, 0x0c, 0xee, 0x66, 0x51, 0xd4, 0x60, 0x04, 0x1b, 0x88, 0x66, 0xa2, 0xc9, 0x31, 0x9c, 0x62, + 0x8a, 0xde, 0x02, 0xf0, 0xee, 0xb0, 0x42, 0x02, 0x9d, 0x67, 0xe5, 0xd4, 0xf3, 0x5c, 0xe6, 0x45, + 0x29, 0x49, 0x01, 0x6b, 0xd4, 0xd0, 0x0d, 0x00, 0xbe, 0x4f, 0x0e, 0x47, 0x3e, 0x61, 0x39, 0x5f, + 0xb5, 0xf1, 0xb2, 0xd4, 0x7c, 0x33, 0x86, 0x3c, 0x7c, 0xb0, 0x3e, 0x1e, 0xd4, 0xb3, 0x62, 0x8a, + 0xf6, 0x39, 0xba, 0x0f, 0xe5, 0x70, 0xd0, 0xef, 0x5b, 0x71, 0xfa, 0x76, 0x33, 0x23, 0x17, 0xc5, + 0x89, 0x2a, 0x93, 0x14, 0x03, 0x58, 0xb2, 0x33, 0x5d, 0x40, 0xe3, 0xf8, 0xe8, 0x55, 0x58, 0x24, + 0xf7, 0x23, 0x12, 0xb8, 0x56, 0xef, 0x36, 0xde, 0x93, 0x29, 0x07, 0x5b, 0xf6, 0x1d, 0x6d, 0x1c, + 0x27, 0xb0, 0xb4, 0x10, 0x29, 0x37, 0x2d, 0x44, 0x32, 0xbf, 0x91, 0x70, 0xcf, 0x87, 0x01, 0x21, + 0xa8, 0x07, 0x45, 0xd7, 0x6b, 0xc5, 0xc7, 0xdb, 0xd5, 0x0c, 0x8e, 0xb7, 0x7d, 0xaf, 0xa5, 0x95, + 0x79, 0xe9, 0x5b, 0x88, 0x39, 0x13, 0xf3, 0x67, 0xc9, 0x2c, 0xeb, 0x4d, 0x2b, 0xb2, 0xbb, 0x3b, + 0x43, 0x1a, 0x34, 0xdf, 0x48, 0x54, 0xbe, 0x7e, 0x55, 0xaf, 0x7c, 0x3d, 0x7c, 0xb0, 0xfe, 0xf9, + 0x69, 0x97, 0x3f, 0xf7, 0x28, 0x85, 0x3a, 0x23, 0xa1, 0x15, 0xc9, 0xde, 0x83, 0x05, 0x4d, 0x42, + 0x71, 0x84, 0x66, 0x55, 0x1a, 0x8a, 0x3d, 0xbe, 0x36, 0x88, 0x75, 0x7e, 0xe6, 0xdf, 0xe7, 0xa0, + 0x2c, 0x6a, 0xce, 0x33, 0x97, 0xda, 0x64, 0xf0, 0x96, 0x9b, 0x1a, 0xbc, 0xf9, 0x50, 0xb2, 0xd9, + 0x0d, 0x96, 0x38, 0xa7, 0xe7, 0xc9, 0x29, 0x85, 0x74, 0xfc, 0x46, 0x4c, 0xc9, 0xc4, 0xdf, 0xb1, + 0xe0, 0x83, 0xde, 0x37, 0xe0, 0xac, 0x4d, 0x73, 0x0f, 0x5b, 0x1d, 0x25, 0x85, 0xb9, 0x0b, 0xc1, + 0x5b, 0x49, 0x8a, 0x8d, 0xcf, 0x08, 0xee, 0x67, 0x53, 0x00, 0x9c, 0xe6, 0x6d, 0xfe, 0x55, 0x1e, + 0x96, 0x12, 0x92, 0xa3, 0x2f, 0x40, 0x65, 0x10, 0xd2, 0x3d, 0x10, 0x87, 0xbd, 0x71, 0xad, 0xf0, + 0xb6, 0x18, 0xc7, 0x31, 0x06, 0xc5, 0xf6, 0xad, 0x30, 0xbc, 0xe7, 0x05, 0x2d, 0xa1, 0xe7, 0x18, + 0xfb, 0x40, 0x8c, 0xe3, 0x18, 0x83, 0x66, 0x7f, 0x77, 0x88, 0x15, 0x90, 0xe0, 0xd0, 0x3b, 0x22, + 0x63, 0xd7, 0x26, 0x0d, 0x05, 0xc2, 0x3a, 0x1e, 0x53, 0x5a, 0xd4, 0x0b, 0xb7, 0x7a, 0x0e, 0x71, + 0x23, 0x2e, 0x66, 0x06, 0x4a, 0x3b, 0xdc, 0x6b, 0xea, 0x14, 0x95, 0xd2, 0x52, 0x00, 0x9c, 0xe6, + 0x8d, 0xbe, 0x65, 0xc0, 0x92, 0x75, 0x2f, 0x54, 0x17, 0xa0, 0xb5, 0xe2, 0xdc, 0xe6, 0x93, 0xb8, + 0x50, 0x6d, 0xac, 0x1c, 0x3f, 0x58, 0x4f, 0xde, 0xb1, 0xe2, 0x24, 0x47, 0xf3, 0xa7, 0x06, 0xc8, + 0x8b, 0xd5, 0xa7, 0x50, 0x12, 0xee, 0x24, 0x4b, 0xc2, 0x8d, 0xf9, 0xf7, 0xc9, 0x94, 0x72, 0xf0, + 0x3e, 0x94, 0x69, 0x36, 0x67, 0xb9, 0x2d, 0xf4, 0x8b, 0x50, 0xb6, 0xf9, 0xa3, 0x38, 0xae, 0x59, + 0xb1, 0x50, 0x40, 0xb1, 0x84, 0xa1, 0xe7, 0xa1, 0x60, 0x05, 0x1d, 0x79, 0x44, 0xb3, 0x5a, 0xea, + 0x66, 0xd0, 0x09, 0x31, 0x1b, 0x35, 0xdf, 0xcf, 0x01, 0x6c, 0x79, 0x7d, 0xdf, 0x0a, 0x48, 0xeb, + 0xd0, 0xfb, 0x7f, 0x9f, 0x39, 0x99, 0x7f, 0x68, 0x00, 0xa2, 0xfa, 0xf0, 0x5c, 0xe2, 0xaa, 0xf2, + 0x07, 0xda, 0x80, 0xaa, 0x2d, 0x47, 0xc5, 0xae, 0x8f, 0x43, 0xe9, 0x18, 0x1d, 0x2b, 0x9c, 0x19, + 0xce, 0xd6, 0x8b, 0x32, 0xe1, 0xe6, 0xbb, 0x3c, 0x5e, 0x6e, 0x56, 0xe2, 0x13, 0xf9, 0xb7, 0xf9, + 0xbd, 0x1c, 0x3c, 0xc7, 0x0d, 0xfa, 0xa6, 0xe5, 0x5a, 0x1d, 0xd2, 0xa7, 0x52, 0xcd, 0x9a, 0x7a, + 0xbf, 0x4d, 0x73, 0x18, 0x47, 0x16, 0x37, 0xe7, 0xb2, 0x49, 0x6e, 0x4b, 0xdc, 0x7a, 0x76, 0x5d, + 0x27, 0xc2, 0x8c, 0x32, 0xf2, 0xa1, 0x22, 0x7b, 0x1f, 0x84, 0x87, 0xc8, 0x82, 0x4b, 0xbc, 0xd1, + 0xae, 0x0a, 0xda, 0x38, 0xe6, 0x62, 0xfe, 0xd8, 0x80, 0xf4, 0xa1, 0xcd, 0xfc, 0x1d, 0xbf, 0xc2, + 0x4b, 0xfb, 0xbb, 0xe4, 0xa5, 0xdb, 0xec, 0xf7, 0x58, 0xe8, 0xab, 0xb0, 0x60, 0x45, 0x11, 0xe9, + 0xfb, 0x11, 0x8b, 0x24, 0xf3, 0x8f, 0x17, 0x49, 0xde, 0xf4, 0x5a, 0x4e, 0xdb, 0x61, 0x91, 0xa4, + 0x4e, 0xce, 0x7c, 0x1d, 0x2a, 0xb2, 0x9a, 0x31, 0xc3, 0x32, 0x5e, 0x4c, 0x54, 0x66, 0xa6, 0x18, + 0x8a, 0x05, 0x8b, 0x7a, 0x22, 0xf4, 0x04, 0x74, 0x62, 0xbe, 0x6f, 0xc0, 0x52, 0xa2, 0x30, 0x9c, + 0x91, 0xec, 0xd4, 0xeb, 0xb5, 0x3d, 0x96, 0xa3, 0x06, 0x8e, 0xcb, 0x43, 0x8d, 0x8a, 0xda, 0xaa, + 0x57, 0x14, 0x08, 0xeb, 0x78, 0xe6, 0x0f, 0x73, 0xb0, 0xcc, 0x6e, 0x85, 0x88, 0xef, 0x85, 0x0e, + 0xcb, 0xb7, 0x5e, 0x80, 0xfc, 0x20, 0xe8, 0x09, 0x79, 0x16, 0x04, 0x85, 0xfc, 0x6d, 0xbc, 0x87, + 0xe9, 0xf8, 0x0c, 0x9b, 0xd2, 0x84, 0x92, 0x6d, 0x6d, 0x53, 0x1f, 0x41, 0xa5, 0x58, 0xe4, 0x11, + 0xed, 0xd6, 0x26, 0x1d, 0xc1, 0x02, 0x82, 0x5e, 0x84, 0x8a, 0x4d, 0x82, 0x88, 0x61, 0x15, 0x18, + 0xd6, 0x22, 0x35, 0xd6, 0x2d, 0x31, 0x86, 0x63, 0x28, 0x3d, 0xa1, 0x8f, 0xc8, 0x88, 0x21, 0x16, + 0x19, 0x22, 0xbf, 0xce, 0xe1, 0x43, 0x58, 0xc2, 0x12, 0x11, 0x45, 0xe9, 0x54, 0x11, 0x45, 0xf9, + 0xa4, 0x88, 0xc2, 0xbc, 0x09, 0xac, 0xe4, 0x90, 0x95, 0x99, 0xbd, 0x0e, 0x15, 0x4a, 0x8e, 0xba, + 0xa4, 0xac, 0x48, 0x36, 0xa1, 0x72, 0xfd, 0xcd, 0x43, 0x1e, 0xc8, 0x98, 0x90, 0x77, 0x2c, 0x7e, + 0xc0, 0xe6, 0xd5, 0xb4, 0x76, 0xc3, 0x70, 0xc0, 0x36, 0x11, 0x05, 0xa2, 0x8b, 0x90, 0x27, 0xf7, + 0x7d, 0x46, 0x32, 0xaf, 0x0e, 0xe1, 0x9d, 0xfb, 0xbe, 0x13, 0x90, 0x90, 0x22, 0x91, 0xfb, 0xbe, + 0x39, 0x00, 0x50, 0x55, 0xf8, 0xac, 0xec, 0xf4, 0x02, 0x14, 0x6c, 0xaf, 0x45, 0x84, 0x81, 0xc6, + 0x64, 0xb6, 0xbc, 0x16, 0xc1, 0x0c, 0x62, 0x7e, 0xc7, 0x80, 0x73, 0xe9, 0xd2, 0xf9, 0xcf, 0xcd, + 0x77, 0xbc, 0x05, 0x2b, 0x63, 0x35, 0xef, 0xac, 0x16, 0x2d, 0x04, 0xd5, 0x64, 0x80, 0xda, 0xa2, + 0x6c, 0x64, 0xcc, 0x1d, 0xe4, 0x35, 0x47, 0xae, 0xad, 0x7a, 0x19, 0x2a, 0xc9, 0xaa, 0x91, 0xf9, + 0xc3, 0x02, 0xa4, 0x0a, 0x00, 0x68, 0xa0, 0xf7, 0x51, 0x18, 0x19, 0xf6, 0x51, 0xc4, 0x2b, 0x34, + 0xa9, 0x97, 0x02, 0x7d, 0x09, 0x8a, 0x7e, 0xd7, 0x0a, 0xa5, 0x8e, 0xd6, 0xa5, 0x8e, 0x0e, 0xe8, + 0xe0, 0x43, 0xbd, 0x4e, 0xc1, 0x46, 0x30, 0xc7, 0xd6, 0x0f, 0xdb, 0xfc, 0x09, 0x0e, 0xe8, 0xeb, + 0xbc, 0x2c, 0x8b, 0x49, 0x38, 0xe8, 0x45, 0x22, 0x98, 0xdf, 0xcf, 0x4a, 0xb3, 0x9c, 0xaa, 0xaa, + 0xcf, 0xf2, 0x77, 0xac, 0x71, 0x44, 0xbf, 0x01, 0xd5, 0x30, 0xb2, 0x82, 0xe8, 0x31, 0x0b, 0x46, + 0xb1, 0xfa, 0x9a, 0x92, 0x08, 0x56, 0xf4, 0xd0, 0x5b, 0x00, 0x6d, 0xc7, 0x75, 0xc2, 0x2e, 0xa3, + 0x5e, 0x7e, 0x3c, 0xe7, 0x7a, 0x25, 0xa6, 0x80, 0x35, 0x6a, 0xe6, 0x07, 0x39, 0x58, 0xd0, 0x7a, + 0xbf, 0x66, 0x30, 0xf8, 0x54, 0xaf, 0x5a, 0x6e, 0xc6, 0x5e, 0xb5, 0x17, 0xa1, 0xe2, 0x7b, 0x3d, + 0xc7, 0x76, 0xe2, 0x1b, 0x22, 0xe6, 0x06, 0x0e, 0xc4, 0x18, 0x8e, 0xa1, 0x28, 0x82, 0xea, 0xdd, + 0x7b, 0x11, 0x3b, 0xe1, 0xe4, 0x0d, 0xd1, 0x3c, 0x17, 0x21, 0xf2, 0xb4, 0x54, 0x4a, 0x96, 0x23, + 0x21, 0x56, 0x8c, 0xa8, 0x2b, 0xeb, 0x04, 0xde, 0xc0, 0xe7, 0x65, 0x47, 0x51, 0x9c, 0x61, 0x7d, + 0x61, 0x21, 0x16, 0x10, 0xf3, 0xe3, 0x3c, 0x80, 0xe6, 0x3e, 0x2f, 0x40, 0x21, 0x20, 0xbe, 0x97, + 0xd6, 0x15, 0xc5, 0xc0, 0x0c, 0x92, 0x70, 0x55, 0xb9, 0x53, 0xb9, 0xaa, 0xfc, 0x89, 0xc9, 0xef, + 0xaf, 0xc1, 0x52, 0x18, 0x76, 0x0f, 0x02, 0x67, 0x68, 0x45, 0xe4, 0x06, 0x19, 0x89, 0x2e, 0x94, + 0xf3, 0xe2, 0x93, 0xa5, 0x66, 0xf3, 0x9a, 0x02, 0xe2, 0x24, 0xee, 0xc4, 0xba, 0x41, 0xf1, 0xe7, + 0x57, 0x37, 0x40, 0x4d, 0x38, 0xef, 0xb8, 0x21, 0xb1, 0x07, 0x81, 0xb8, 0x8a, 0xb8, 0xe6, 0x85, + 0x11, 0x9d, 0x54, 0x89, 0x39, 0x8f, 0x17, 0x04, 0xa1, 0xf3, 0xbb, 0x93, 0x90, 0xf0, 0xe4, 0x6f, + 0xa9, 0x3e, 0x25, 0x80, 0xed, 0x9a, 0x8a, 0xe6, 0x23, 0xc5, 0x38, 0x8e, 0x31, 0xcc, 0xef, 0xe6, + 0xe0, 0xbc, 0x5a, 0x5c, 0x1a, 0x9e, 0x38, 0x6d, 0x3a, 0x43, 0x76, 0x1b, 0xcb, 0x4b, 0x40, 0xda, + 0xce, 0x88, 0x8b, 0xc8, 0xbc, 0x48, 0xc4, 0xf6, 0x87, 0x86, 0x85, 0x7e, 0x41, 0x14, 0xcb, 0x52, + 0xab, 0x4e, 0xc9, 0x6a, 0x55, 0xb0, 0x97, 0xa1, 0x64, 0x3b, 0x7e, 0x97, 0x04, 0xe9, 0xda, 0x05, + 0xc5, 0x6b, 0x0e, 0xee, 0x30, 0x54, 0x81, 0x22, 0x03, 0xa9, 0xd6, 0x23, 0x03, 0x29, 0x96, 0x5e, + 0x6f, 0xc2, 0x59, 0xfa, 0xdc, 0x76, 0xdc, 0x0e, 0x09, 0xfc, 0xc0, 0x71, 0x23, 0xb6, 0xb8, 0x55, + 0x6d, 0x41, 0x48, 0x10, 0x5d, 0x51, 0x60, 0x9c, 0xc6, 0x37, 0xff, 0xc3, 0x80, 0xcf, 0x4e, 0xd4, + 0xc6, 0x53, 0xa8, 0x0e, 0x0c, 0x92, 0xd5, 0x81, 0x83, 0xb9, 0x0a, 0x9e, 0x13, 0xa6, 0x30, 0xa5, + 0x56, 0xf0, 0xb1, 0x01, 0xcb, 0x0a, 0xff, 0xff, 0x56, 0xd7, 0xb4, 0x92, 0x7b, 0xca, 0xe4, 0x3e, + 0x60, 0x93, 0xe3, 0x05, 0x84, 0x4d, 0x5b, 0x76, 0x32, 0x9e, 0x70, 0xd4, 0x0f, 0xa1, 0xc4, 0x7a, + 0x16, 0xa4, 0x84, 0xfb, 0x19, 0x94, 0x9e, 0x39, 0x73, 0x16, 0xee, 0xa9, 0x2c, 0x8b, 0xbd, 0x86, + 0x58, 0x70, 0x33, 0xfb, 0x50, 0x4b, 0xa2, 0x6f, 0x13, 0xea, 0xb2, 0x66, 0x94, 0x7a, 0x03, 0xaa, + 0x16, 0xfb, 0x6a, 0x6f, 0x60, 0xa5, 0x5b, 0x22, 0x37, 0x25, 0x00, 0x2b, 0x1c, 0xf3, 0xcf, 0x0c, + 0x78, 0x66, 0x82, 0x78, 0x19, 0xc6, 0xc1, 0xec, 0x28, 0xc8, 0x3f, 0xaa, 0x63, 0xb4, 0x45, 0xda, + 0x96, 0x0c, 0x5d, 0xb4, 0x40, 0x67, 0x9b, 0x0f, 0x63, 0x09, 0x37, 0xff, 0xd5, 0x80, 0xb3, 0x49, + 0x59, 0x43, 0x74, 0x1d, 0x10, 0x9f, 0xcc, 0xb6, 0x13, 0xda, 0xde, 0x90, 0x04, 0x23, 0x3a, 0x73, + 0x2e, 0xf5, 0xaa, 0xa0, 0x84, 0x36, 0xc7, 0x30, 0xf0, 0x84, 0xaf, 0xd0, 0x77, 0x58, 0x6d, 0x49, + 0x6a, 0x5b, 0x2e, 0x7c, 0x33, 0xb3, 0x85, 0x57, 0x2b, 0xa9, 0xc7, 0x0c, 0x31, 0x3f, 0xac, 0x33, + 0x37, 0xff, 0x32, 0x07, 0x8b, 0xf2, 0xf3, 0x6d, 0xa7, 0xdd, 0xa6, 0xfa, 0x66, 0xae, 0x58, 0x4c, + 0x2e, 0xd6, 0x37, 0xf3, 0xd3, 0x98, 0xc3, 0xa8, 0xbe, 0x8f, 0x1c, 0xb7, 0x95, 0xce, 0x07, 0x6e, + 0x38, 0x6e, 0x0b, 0x33, 0x48, 0xb2, 0x69, 0x36, 0x7f, 0x72, 0xd3, 0x6c, 0x6c, 0x09, 0x85, 0x47, + 0x45, 0x45, 0xbc, 0xcd, 0x53, 0xf9, 0x52, 0xed, 0x38, 0x3f, 0x54, 0x20, 0xac, 0xe3, 0x51, 0x49, + 0x7a, 0xce, 0x90, 0xf0, 0x8f, 0x4a, 0x49, 0x49, 0xf6, 0x24, 0x00, 0x2b, 0x1c, 0x2a, 0x49, 0xcb, + 0x69, 0xb7, 0x45, 0x2a, 0x1b, 0x4b, 0x42, 0xb5, 0x83, 0x19, 0xc4, 0xfc, 0x37, 0x76, 0x72, 0x4f, + 0xb9, 0xd6, 0xcf, 0x4a, 0x83, 0x52, 0x21, 0xf9, 0x47, 0xed, 0x42, 0xa5, 0xe3, 0xc2, 0x0c, 0x3a, + 0x7e, 0x15, 0x16, 0xef, 0x86, 0x9e, 0x7b, 0xe0, 0x39, 0x2e, 0xeb, 0xca, 0x2a, 0xaa, 0x3b, 0xb5, + 0xeb, 0xcd, 0x5b, 0xfb, 0x72, 0x1c, 0x27, 0xb0, 0xcc, 0x1f, 0x17, 0xe1, 0xb9, 0xf8, 0x56, 0x8b, + 0x44, 0xf7, 0xbc, 0xe0, 0xc8, 0x71, 0x3b, 0x2c, 0x87, 0xff, 0x81, 0x01, 0x8b, 0x5c, 0xd7, 0xa2, + 0xdb, 0x88, 0xdf, 0x9f, 0xd9, 0x59, 0xdc, 0x9f, 0x25, 0x38, 0xd5, 0x0f, 0x35, 0x2e, 0xa9, 0x4e, + 0x23, 0x1d, 0x84, 0x13, 0xe2, 0xa0, 0x77, 0x01, 0x64, 0x67, 0x70, 0x3b, 0x8b, 0xe6, 0x68, 0x29, + 0x1c, 0x26, 0x6d, 0x15, 0x9e, 0x1c, 0xc6, 0x1c, 0xb0, 0xc6, 0x0d, 0x7d, 0xdb, 0x80, 0x52, 0x8f, + 0x6b, 0x25, 0xcf, 0x18, 0xff, 0x66, 0xf6, 0x5a, 0xd1, 0xf5, 0x11, 0x9f, 0xf4, 0x42, 0x13, 0x82, + 0x39, 0xc2, 0x50, 0x76, 0xdc, 0x4e, 0x40, 0x42, 0x19, 0xe9, 0x7f, 0x5e, 0xf3, 0xaf, 0x75, 0xdb, + 0x0b, 0x08, 0xf3, 0xa6, 0x9e, 0xd5, 0x6a, 0x58, 0x3d, 0xcb, 0xb5, 0x49, 0xb0, 0xcb, 0xd1, 0xd5, + 0x11, 0x29, 0x06, 0xb0, 0x24, 0x34, 0x76, 0x39, 0x5b, 0x9c, 0xe5, 0x72, 0x76, 0xf5, 0x35, 0x58, + 0x19, 0x5b, 0xc6, 0xd3, 0xf4, 0x7d, 0xad, 0x7e, 0x19, 0x16, 0x1e, 0xb7, 0x65, 0xec, 0xa7, 0x45, + 0x75, 0xce, 0xed, 0x7b, 0x2d, 0x76, 0x3b, 0x1a, 0xa8, 0xd5, 0x14, 0xa1, 0x47, 0x56, 0xb6, 0xa1, + 0xb5, 0x9a, 0xc6, 0x83, 0x58, 0xe7, 0x47, 0x2d, 0xd3, 0xb7, 0x02, 0xe2, 0x3e, 0x51, 0xcb, 0x3c, + 0x88, 0x39, 0x60, 0x8d, 0x1b, 0x22, 0xa2, 0x93, 0x28, 0x3f, 0x77, 0xe2, 0x27, 0x2b, 0x6f, 0x93, + 0xba, 0x89, 0x68, 0x02, 0xb4, 0xec, 0x26, 0xec, 0x55, 0x54, 0x0d, 0x5e, 0xcf, 0x7c, 0x23, 0xf0, + 0x56, 0x8c, 0xe4, 0x18, 0x4e, 0x31, 0xa7, 0x21, 0xbb, 0x5c, 0x81, 0x37, 0x48, 0xc0, 0x7e, 0x55, + 0x90, 0x0a, 0xd9, 0x71, 0x12, 0x8c, 0xd3, 0xf8, 0x5a, 0x7b, 0x41, 0x69, 0x6a, 0x07, 0xe6, 0x51, + 0xdc, 0x49, 0x54, 0xce, 0xb6, 0x93, 0x08, 0xc6, 0xbb, 0x88, 0xcc, 0x1f, 0x19, 0x70, 0x4e, 0x4a, + 0x7d, 0x6b, 0x48, 0x82, 0xc0, 0x69, 0x31, 0xbf, 0xc0, 0xc1, 0x2a, 0x46, 0x89, 0xfd, 0xc2, 0x35, + 0x09, 0xc0, 0x0a, 0x07, 0x5d, 0x9d, 0xd4, 0xf9, 0xc6, 0x3d, 0xd3, 0xe9, 0x7a, 0xd4, 0x5e, 0x82, + 0x32, 0x0f, 0x78, 0xc2, 0x74, 0x39, 0x49, 0x04, 0x52, 0x58, 0xc2, 0xcd, 0xff, 0x34, 0x40, 0xdf, + 0x1d, 0xb3, 0x79, 0xcd, 0x97, 0xa0, 0x3c, 0x14, 0x4b, 0x97, 0xba, 0x1b, 0x90, 0x4b, 0x26, 0xe1, + 0xb1, 0x83, 0xcd, 0xcf, 0x16, 0xa2, 0x14, 0x4e, 0x11, 0xa2, 0x14, 0xa7, 0x7a, 0xe4, 0x17, 0x20, + 0x3f, 0x70, 0x5a, 0x22, 0xca, 0x50, 0xd5, 0xfe, 0xdd, 0x6d, 0x4c, 0xc7, 0xcd, 0x7f, 0xce, 0xab, + 0x0c, 0x41, 0x54, 0xb5, 0x3e, 0x15, 0xd3, 0x7e, 0x35, 0xbe, 0xda, 0xe1, 0x33, 0x7f, 0x3e, 0x79, + 0xb5, 0xf3, 0xf0, 0xc1, 0x3a, 0xf0, 0xe9, 0xb2, 0xc2, 0xf4, 0x84, 0x8b, 0x9e, 0xf2, 0x09, 0xb5, + 0xc7, 0xcb, 0x50, 0xe9, 0x7a, 0xde, 0x11, 0xeb, 0x73, 0xaa, 0x24, 0x58, 0x54, 0xae, 0x89, 0xf1, + 0x87, 0xda, 0x33, 0x8e, 0xb1, 0xd1, 0x26, 0x54, 0xe9, 0x33, 0x2b, 0x7a, 0x8a, 0x16, 0xa9, 0x8b, + 0xf1, 0x5e, 0x90, 0x80, 0x09, 0xf5, 0x51, 0xf5, 0x15, 0x55, 0x18, 0x6b, 0x13, 0x65, 0x24, 0x20, + 0xa9, 0xb0, 0xa6, 0x04, 0x60, 0x85, 0x63, 0x7e, 0xa2, 0x2d, 0xb3, 0xb8, 0xfc, 0xfa, 0x54, 0x2c, + 0xf3, 0xe5, 0xd4, 0x32, 0x5f, 0x18, 0x5b, 0xe6, 0x65, 0xd5, 0x65, 0x99, 0x58, 0xea, 0xa7, 0x79, + 0x26, 0xd2, 0x89, 0xd0, 0xc5, 0x63, 0x86, 0xa2, 0x5d, 0x8a, 0xd0, 0xd5, 0xc6, 0x0c, 0xc2, 0x3d, + 0xc1, 0x3b, 0x03, 0x27, 0x20, 0xe1, 0x41, 0x30, 0x70, 0x1d, 0xb7, 0xc3, 0x4c, 0xa3, 0xa2, 0x7b, + 0x82, 0x04, 0x18, 0xa7, 0xf1, 0xcd, 0xbf, 0xc8, 0xd1, 0x24, 0x31, 0xd1, 0x75, 0x89, 0xbe, 0x00, + 0x95, 0x40, 0xfe, 0x5e, 0x2d, 0x55, 0x94, 0x8a, 0x7f, 0xa9, 0x16, 0x63, 0xa0, 0xaf, 0x01, 0xb4, + 0x88, 0xdf, 0xf3, 0x46, 0xac, 0xe4, 0x5c, 0x38, 0x75, 0xc9, 0x39, 0xf6, 0xf2, 0xdb, 0x31, 0x15, + 0xac, 0x51, 0x44, 0xab, 0x90, 0x73, 0x5a, 0x6c, 0x35, 0xf3, 0x0d, 0x10, 0xb8, 0xb9, 0xdd, 0x6d, + 0x9c, 0x73, 0x5a, 0x5a, 0x53, 0x45, 0xe9, 0xe9, 0x35, 0x55, 0x98, 0x7f, 0xcb, 0x9c, 0x15, 0x9f, + 0xfe, 0x4d, 0x59, 0xa1, 0xf9, 0x1c, 0x94, 0xac, 0x41, 0xd4, 0xf5, 0xc6, 0x5a, 0xc3, 0x36, 0xd9, + 0x28, 0x16, 0x50, 0xb4, 0x07, 0x85, 0x16, 0xcd, 0xe0, 0x72, 0xa7, 0x56, 0x94, 0xca, 0xe0, 0x68, + 0xa2, 0xc7, 0xa8, 0xa0, 0xe7, 0xa1, 0x10, 0x59, 0x1d, 0x59, 0x26, 0x67, 0xd7, 0x3a, 0xec, 0xd7, + 0x16, 0x6c, 0x54, 0x3f, 0x99, 0x0a, 0x27, 0x5c, 0x41, 0xff, 0x79, 0x01, 0x96, 0x12, 0x37, 0x19, + 0x09, 0x2b, 0x30, 0x4e, 0xb4, 0x82, 0x8b, 0x50, 0xf4, 0x83, 0x81, 0xcb, 0xe7, 0x55, 0x51, 0x07, + 0x03, 0xb5, 0x33, 0x82, 0x39, 0x8c, 0xea, 0xa8, 0x15, 0x8c, 0xf0, 0xc0, 0x15, 0x17, 0x7d, 0xb1, + 0x8e, 0xb6, 0xd9, 0x28, 0x16, 0x50, 0xf4, 0x1e, 0x2c, 0x86, 0x6c, 0x03, 0x06, 0x56, 0x44, 0x3a, + 0xb2, 0x77, 0xfe, 0xea, 0xdc, 0x5d, 0xd3, 0x9c, 0x1c, 0x8f, 0xef, 0xf5, 0x11, 0x9c, 0x60, 0x87, + 0xbe, 0x65, 0xe8, 0x9d, 0xe2, 0xa5, 0xb9, 0x2b, 0x8b, 0xe9, 0x1b, 0x22, 0x6e, 0x5d, 0x8f, 0x6e, + 0x18, 0xf7, 0x63, 0xcb, 0x2e, 0x3f, 0x01, 0xcb, 0x86, 0x09, 0xad, 0x42, 0x2f, 0x43, 0xb5, 0x6f, + 0xb9, 0x4e, 0x9b, 0x84, 0x51, 0x58, 0xab, 0x30, 0x7b, 0x62, 0x3f, 0x51, 0xbc, 0x29, 0x07, 0xb1, + 0x82, 0x9b, 0xdf, 0x34, 0xe0, 0xfc, 0xc4, 0x69, 0x3d, 0xb5, 0xaa, 0x01, 0x3d, 0xb9, 0x9e, 0x99, + 0x70, 0xf7, 0x86, 0x86, 0x4f, 0xa6, 0xcd, 0x5f, 0xdc, 0xec, 0x2d, 0x4d, 0x5d, 0xb1, 0xd3, 0x9d, + 0x9a, 0xea, 0xe4, 0xca, 0x3f, 0xc5, 0x93, 0xeb, 0x0f, 0x0c, 0xd0, 0x7e, 0x36, 0x82, 0x7e, 0x1b, + 0xaa, 0xd6, 0x20, 0xf2, 0xfa, 0x56, 0x44, 0x5a, 0x22, 0x73, 0xdc, 0xcf, 0xe4, 0x07, 0x2a, 0x9b, + 0x92, 0x2a, 0xd7, 0x57, 0xfc, 0x8a, 0x15, 0x3f, 0xf3, 0x2b, 0x7c, 0xf9, 0x52, 0x1f, 0xa8, 0x83, + 0xc4, 0x98, 0x7e, 0x90, 0x98, 0xff, 0x2e, 0xe6, 0x21, 0xa2, 0x92, 0xcb, 0xa9, 0x96, 0x9c, 0xd9, + 0x1d, 0xfa, 0x08, 0xc0, 0x8e, 0x7b, 0xf4, 0x32, 0xf8, 0x75, 0x86, 0x6a, 0xf8, 0xd3, 0x7f, 0x3b, + 0x20, 0xc7, 0xb0, 0xc6, 0x2c, 0x61, 0x2f, 0xf9, 0x93, 0xec, 0xc5, 0xfc, 0x17, 0x03, 0x12, 0x47, + 0x16, 0xea, 0x43, 0x91, 0x4a, 0x30, 0xca, 0xa0, 0x9d, 0x50, 0xa7, 0x4b, 0x6d, 0x69, 0xd4, 0xa8, + 0x52, 0x8d, 0xb3, 0x47, 0xcc, 0xb9, 0x20, 0x47, 0x04, 0x23, 0x5c, 0x45, 0x37, 0x32, 0xe2, 0x46, + 0x63, 0x19, 0xf1, 0x23, 0xf4, 0x38, 0xaa, 0x31, 0x2f, 0xc3, 0xca, 0x98, 0x44, 0xd4, 0x2c, 0x58, + 0x87, 0x52, 0xda, 0x2c, 0x58, 0x0f, 0x13, 0xe6, 0x30, 0xf3, 0x03, 0x03, 0xce, 0xa5, 0xc9, 0xa3, + 0x3f, 0x31, 0x60, 0x25, 0x4c, 0xd3, 0x7b, 0x22, 0x5a, 0x8b, 0x73, 0xcc, 0x31, 0x10, 0x1e, 0x97, + 0x80, 0xae, 0x68, 0xba, 0xdf, 0x37, 0x71, 0x0d, 0x69, 0x9c, 0x74, 0x0d, 0xa9, 0x2e, 0x1b, 0xf7, + 0xd5, 0xa5, 0xf1, 0x23, 0x2e, 0x1b, 0xd9, 0x1f, 0x1f, 0xe9, 0x2d, 0x56, 0xf9, 0x59, 0x5b, 0xac, + 0x0a, 0x8f, 0x68, 0xb1, 0x52, 0x7d, 0x5d, 0xc5, 0x69, 0x7d, 0x5d, 0x8d, 0xfa, 0x87, 0x9f, 0xac, + 0x9d, 0xf9, 0xc9, 0x27, 0x6b, 0x67, 0x3e, 0xfa, 0x64, 0xed, 0xcc, 0x37, 0x8f, 0xd7, 0x8c, 0x0f, + 0x8f, 0xd7, 0x8c, 0x9f, 0x1c, 0xaf, 0x19, 0x1f, 0x1d, 0xaf, 0x19, 0xff, 0x74, 0xbc, 0x66, 0xfc, + 0xd1, 0xcf, 0xd6, 0xce, 0xbc, 0x55, 0x91, 0xaa, 0xfd, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, + 0x17, 0x17, 0xc7, 0x5e, 0x4b, 0x00, 0x00, } diff --git a/pkg/apis/application/v1alpha1/generated.proto b/pkg/apis/application/v1alpha1/generated.proto index 4ae7537186b67..3b220d89c53f4 100644 --- a/pkg/apis/application/v1alpha1/generated.proto +++ b/pkg/apis/application/v1alpha1/generated.proto @@ -484,17 +484,51 @@ message ProjectRole { // Repository is a Git repository holding application configurations message Repository { + // URL of the repo optional string repo = 1; + // Username for authenticating at the repo server optional string username = 2; + // Password for authenticating at the repo server optional string password = 3; + // SSH private key data for authenticating at the repo server optional string sshPrivateKey = 4; optional ConnectionState connectionState = 5; + // InsecureIgnoreHostKey should not be used anymore, Insecure is favoured optional bool insecureIgnoreHostKey = 6; + + // Whether the repo is insecure + optional bool insecure = 7; +} + +// A RepositoryCertificate is either SSH known hosts entry or TLS certificate +message RepositoryCertificate { + // Name of the server the certificate is intended for + optional string servername = 1; + + // Type of certificate - currently "https" or "ssh" + optional string type = 2; + + // The sub type of the cert, i.e. "ssh-rsa" + optional string cipher = 3; + + // Actual certificate data, protocol dependent + optional bytes certdata = 4; + + // Certificate fingerprint + optional string certfingerprint = 5; +} + +// RepositoryCertificateList is a collection of RepositoryCertificates +message RepositoryCertificateList { + optional k8s.io.apimachinery.pkg.apis.meta.v1.ListMeta metadata = 1; + + // List of certificates to be processed + repeated RepositoryCertificate items = 2; } // RepositoryList is a collection of Repositories. diff --git a/pkg/apis/application/v1alpha1/openapi_generated.go b/pkg/apis/application/v1alpha1/openapi_generated.go index fd9d4a28d3242..d68c05b5343b0 100644 --- a/pkg/apis/application/v1alpha1/openapi_generated.go +++ b/pkg/apis/application/v1alpha1/openapi_generated.go @@ -55,6 +55,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.OperationState": schema_pkg_apis_application_v1alpha1_OperationState(ref), "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.ProjectRole": schema_pkg_apis_application_v1alpha1_ProjectRole(ref), "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.Repository": schema_pkg_apis_application_v1alpha1_Repository(ref), + "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.RepositoryCertificate": schema_pkg_apis_application_v1alpha1_RepositoryCertificate(ref), + "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.RepositoryCertificateList": schema_pkg_apis_application_v1alpha1_RepositoryCertificateList(ref), "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.RepositoryList": schema_pkg_apis_application_v1alpha1_RepositoryList(ref), "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.ResourceAction": schema_pkg_apis_application_v1alpha1_ResourceAction(ref), "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.ResourceActionDefinition": schema_pkg_apis_application_v1alpha1_ResourceActionDefinition(ref), @@ -1749,26 +1751,30 @@ func schema_pkg_apis_application_v1alpha1_Repository(ref common.ReferenceCallbac Properties: map[string]spec.Schema{ "repo": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "URL of the repo", + Type: []string{"string"}, + Format: "", }, }, "username": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "Username for authenticating at the repo server", + Type: []string{"string"}, + Format: "", }, }, "password": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "Password for authenticating at the repo server", + Type: []string{"string"}, + Format: "", }, }, "sshPrivateKey": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "SSH private key data for authenticating at the repo server", + Type: []string{"string"}, + Format: "", }, }, "connectionState": { @@ -1778,8 +1784,16 @@ func schema_pkg_apis_application_v1alpha1_Repository(ref common.ReferenceCallbac }, "insecureIgnoreHostKey": { SchemaProps: spec.SchemaProps{ - Type: []string{"boolean"}, - Format: "", + Description: "InsecureIgnoreHostKey should not be used anymore, Insecure is favoured", + Type: []string{"boolean"}, + Format: "", + }, + }, + "insecure": { + SchemaProps: spec.SchemaProps{ + Description: "Whether the repo is insecure", + Type: []string{"boolean"}, + Format: "", }, }, }, @@ -1791,6 +1805,89 @@ func schema_pkg_apis_application_v1alpha1_Repository(ref common.ReferenceCallbac } } +func schema_pkg_apis_application_v1alpha1_RepositoryCertificate(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "A RepositoryCertificate is either SSH known hosts entry or TLS certificate", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "servername": { + SchemaProps: spec.SchemaProps{ + Description: "Name of the server the certificate is intended for", + Type: []string{"string"}, + Format: "", + }, + }, + "type": { + SchemaProps: spec.SchemaProps{ + Description: "Type of certificate - currently \"https\" or \"ssh\"", + Type: []string{"string"}, + Format: "", + }, + }, + "cipher": { + SchemaProps: spec.SchemaProps{ + Description: "The sub type of the cert, i.e. \"ssh-rsa\"", + Type: []string{"string"}, + Format: "", + }, + }, + "certdata": { + SchemaProps: spec.SchemaProps{ + Description: "Actual certificate data, protocol dependent", + Type: []string{"string"}, + Format: "byte", + }, + }, + "certfingerprint": { + SchemaProps: spec.SchemaProps{ + Description: "Certificate fingerprint", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"servername", "type", "cipher", "certdata", "certfingerprint"}, + }, + }, + } +} + +func schema_pkg_apis_application_v1alpha1_RepositoryCertificateList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RepositoryCertificateList is a collection of RepositoryCertificates", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "metadata": { + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "List of certificates to be processed", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.RepositoryCertificate"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1.RepositoryCertificate", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, + } +} + func schema_pkg_apis_application_v1alpha1_RepositoryList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/apis/application/v1alpha1/types.go b/pkg/apis/application/v1alpha1/types.go index 7a6915a06546c..f5b7af33dfac5 100644 --- a/pkg/apis/application/v1alpha1/types.go +++ b/pkg/apis/application/v1alpha1/types.go @@ -881,12 +881,19 @@ type ResourceActionParam struct { // Repository is a Git repository holding application configurations type Repository struct { - Repo string `json:"repo" protobuf:"bytes,1,opt,name=repo"` - Username string `json:"username,omitempty" protobuf:"bytes,2,opt,name=username"` - Password string `json:"password,omitempty" protobuf:"bytes,3,opt,name=password"` - SSHPrivateKey string `json:"sshPrivateKey,omitempty" protobuf:"bytes,4,opt,name=sshPrivateKey"` - ConnectionState ConnectionState `json:"connectionState,omitempty" protobuf:"bytes,5,opt,name=connectionState"` - InsecureIgnoreHostKey bool `json:"insecureIgnoreHostKey,omitempty" protobuf:"bytes,6,opt,name=insecureIgnoreHostKey"` + // URL of the repo + Repo string `json:"repo" protobuf:"bytes,1,opt,name=repo"` + // Username for authenticating at the repo server + Username string `json:"username,omitempty" protobuf:"bytes,2,opt,name=username"` + // Password for authenticating at the repo server + Password string `json:"password,omitempty" protobuf:"bytes,3,opt,name=password"` + // SSH private key data for authenticating at the repo server + SSHPrivateKey string `json:"sshPrivateKey,omitempty" protobuf:"bytes,4,opt,name=sshPrivateKey"` + ConnectionState ConnectionState `json:"connectionState,omitempty" protobuf:"bytes,5,opt,name=connectionState"` + // InsecureIgnoreHostKey should not be used anymore, Insecure is favoured + InsecureIgnoreHostKey bool `json:"insecureIgnoreHostKey,omitempty" protobuf:"bytes,6,opt,name=insecureIgnoreHostKey"` + // Whether the repo is insecure + Insecure bool `json:"insecure,omitempty" protobuf:"bytes,7,opt,name=insecure"` } func (m *Repository) HasCredentials() bool { @@ -899,6 +906,7 @@ func (m *Repository) CopyCredentialsFrom(source *Repository) { m.Password = source.Password m.SSHPrivateKey = source.SSHPrivateKey m.InsecureIgnoreHostKey = source.InsecureIgnoreHostKey + m.Insecure = source.Insecure } } @@ -908,6 +916,27 @@ type RepositoryList struct { Items []Repository `json:"items" protobuf:"bytes,2,rep,name=items"` } +// A RepositoryCertificate is either SSH known hosts entry or TLS certificate +type RepositoryCertificate struct { + // Name of the server the certificate is intended for + ServerName string `json:"servername" protobuf:"bytes,1,opt,name=servername"` + // Type of certificate - currently "https" or "ssh" + CertType string `json:"type" protobuf:"bytes,2,opt,name=type"` + // The sub type of the cert, i.e. "ssh-rsa" + CertSubType string `json:"cipher" protobuf:"bytes,3,opt,name=cipher"` + // Actual certificate data, protocol dependent + CertData []byte `json:"certdata" protobuf:"bytes,4,opt,name=certdata"` + // Certificate fingerprint + CertFingerprint string `json:"certfingerprint" protobuf:"bytes,5,opt,name=certfingerprint"` +} + +// RepositoryCertificateList is a collection of RepositoryCertificates +type RepositoryCertificateList struct { + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + // List of certificates to be processed + Items []RepositoryCertificate `json:"items" protobuf:"bytes,2,rep,name=items"` +} + // AppProjectList is list of AppProject resources // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type AppProjectList struct { diff --git a/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go index 04a73de7faf46..70abbf23e5c0d 100644 --- a/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go @@ -1033,6 +1033,51 @@ func (in *Repository) DeepCopy() *Repository { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RepositoryCertificate) DeepCopyInto(out *RepositoryCertificate) { + *out = *in + if in.CertData != nil { + in, out := &in.CertData, &out.CertData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryCertificate. +func (in *RepositoryCertificate) DeepCopy() *RepositoryCertificate { + if in == nil { + return nil + } + out := new(RepositoryCertificate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RepositoryCertificateList) DeepCopyInto(out *RepositoryCertificateList) { + *out = *in + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]RepositoryCertificate, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryCertificateList. +func (in *RepositoryCertificateList) DeepCopy() *RepositoryCertificateList { + if in == nil { + return nil + } + out := new(RepositoryCertificateList) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RepositoryList) DeepCopyInto(out *RepositoryList) { *out = *in diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 6bc6a40c962ac..ffeba0c4e92fd 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -524,7 +524,7 @@ func (s *Service) newClientResolveRevision(repo *v1alpha1.Repository, revision s func (s *Service) newClient(repo *v1alpha1.Repository) (git.Client, error) { appPath := tempRepoPath(git.NormalizeGitURL(repo.Repo)) - return s.gitFactory.NewClient(repo.Repo, appPath, repo.Username, repo.Password, repo.SSHPrivateKey, repo.InsecureIgnoreHostKey) + return s.gitFactory.NewClient(repo.Repo, appPath, repo.Username, repo.Password, repo.SSHPrivateKey, (repo.InsecureIgnoreHostKey || repo.Insecure)) } func runCommand(command v1alpha1.Command, path string, env []string) (string, error) { @@ -753,7 +753,7 @@ func newCreds(repo *v1alpha1.Repository) git.Creds { return git.NewHTTPSCreds(repo.Username, repo.Password) } if repo.SSHPrivateKey != "" { - return git.NewSSHCreds(repo.SSHPrivateKey, repo.InsecureIgnoreHostKey) + return git.NewSSHCreds(repo.SSHPrivateKey, (repo.InsecureIgnoreHostKey || repo.Insecure)) } return git.NopCreds{} } diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go index 7227ecadba189..3d8096460f1c9 100644 --- a/reposerver/repository/repository_test.go +++ b/reposerver/repository/repository_test.go @@ -64,7 +64,7 @@ func (f *fakeGitClientFactory) NewClient(repoURL, path, username, password, sshP func TestGenerateYamlManifestInDir(t *testing.T) { // update this value if we add/remove manifests - const countOfManifests = 23 + const countOfManifests = 25 q := ManifestRequest{ ApplicationSource: &argoappv1.ApplicationSource{}, diff --git a/server/account/account_test.go b/server/account/account_test.go index 9140b25e930b9..afc8388e98086 100644 --- a/server/account/account_test.go +++ b/server/account/account_test.go @@ -31,6 +31,9 @@ func newTestAccountServer(ctx context.Context) (*fake.Clientset, *Server, *sessi ObjectMeta: metav1.ObjectMeta{ Name: "argocd-cm", Namespace: testNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, }, &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ diff --git a/server/application/application_test.go b/server/application/application_test.go index caa8bf7fb0d2a..b4436a1867ad4 100644 --- a/server/application/application_test.go +++ b/server/application/application_test.go @@ -90,7 +90,13 @@ func fakeListDirResponse() *repository.FileList { // return an ApplicationServiceServer which returns fake data func newTestAppServer(objects ...runtime.Object) *Server { kubeclientset := fake.NewSimpleClientset(&v1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{Namespace: testNamespace, Name: "argocd-cm"}, + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "argocd-cm", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, }, &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "argocd-secret", diff --git a/server/badge/badge_test.go b/server/badge/badge_test.go index 968a3e3ebefc9..b84acbf2bb257 100644 --- a/server/badge/badge_test.go +++ b/server/badge/badge_test.go @@ -25,7 +25,13 @@ var ( }, } argoCDCm = corev1.ConfigMap{ - ObjectMeta: v1.ObjectMeta{Name: "argocd-cm", Namespace: "default"}, + ObjectMeta: v1.ObjectMeta{ + Name: "argocd-cm", + Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, Data: map[string]string{ "statusbadge.enabled": "true", }, diff --git a/server/certificate/certificate.go b/server/certificate/certificate.go new file mode 100644 index 0000000000000..a8ffaeaf9d3e2 --- /dev/null +++ b/server/certificate/certificate.go @@ -0,0 +1,85 @@ +package certificate + +import ( + "golang.org/x/net/context" + + certificatepkg "github.com/argoproj/argo-cd/pkg/apiclient/certificate" + appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/reposerver" + "github.com/argoproj/argo-cd/server/rbacpolicy" + "github.com/argoproj/argo-cd/util/cache" + "github.com/argoproj/argo-cd/util/db" + "github.com/argoproj/argo-cd/util/rbac" +) + +// Server provides a Certificate service +type Server struct { + db db.ArgoDB + repoClientset reposerver.Clientset + enf *rbac.Enforcer + cache *cache.Cache +} + +// NewServer returns a new instance of the Certificate service +func NewServer( + repoClientset reposerver.Clientset, + db db.ArgoDB, + enf *rbac.Enforcer, + cache *cache.Cache, +) *Server { + return &Server{ + db: db, + repoClientset: repoClientset, + enf: enf, + cache: cache, + } +} + +// TODO: RBAC policies are currently an all-or-nothing approach, so there is no +// fine grained control for certificate manipulation. Either a user has access +// to a given certificate operation (get/create/delete), or it doesn't. + +// Returns a list of configured certificates that match the query +func (s *Server) List(ctx context.Context, q *certificatepkg.RepositoryCertificateQuery) (*appsv1.RepositoryCertificateList, error) { + if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceCertificates, rbacpolicy.ActionGet, ""); err != nil { + return nil, err + } + certList, err := s.db.ListRepoCertificates(ctx, &db.CertificateListSelector{ + HostNamePattern: q.GetHostNamePattern(), + CertType: q.GetCertType(), + CertSubType: q.GetCertSubType(), + }) + if err != nil { + return nil, err + } + return certList, nil +} + +// Batch creates certificates for verifying repositories +func (s *Server) Create(ctx context.Context, q *certificatepkg.RepositoryCertificateCreateRequest) (*appsv1.RepositoryCertificateList, error) { + if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceCertificates, rbacpolicy.ActionCreate, ""); err != nil { + return nil, err + } + certs, err := s.db.CreateRepoCertificate(ctx, q.Certificates, q.Upsert) + if err != nil { + return nil, err + } + + return certs, nil +} + +// Batch deletes a list of certificates that match the query +func (s *Server) Delete(ctx context.Context, q *certificatepkg.RepositoryCertificateQuery) (*appsv1.RepositoryCertificateList, error) { + if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceCertificates, rbacpolicy.ActionDelete, ""); err != nil { + return nil, err + } + certs, err := s.db.RemoveRepoCertificates(ctx, &db.CertificateListSelector{ + HostNamePattern: q.GetHostNamePattern(), + CertType: q.GetCertType(), + CertSubType: q.GetCertSubType(), + }) + if err != nil { + return nil, err + } + return certs, nil +} diff --git a/server/certificate/certificate.proto b/server/certificate/certificate.proto new file mode 100644 index 0000000000000..9c8f50d46c6ad --- /dev/null +++ b/server/certificate/certificate.proto @@ -0,0 +1,51 @@ +syntax = "proto3"; +option go_package = "github.com/argoproj/argo-cd/pkg/apiclient/certificate"; + +// Certificate Service +// +// Certificate Service API performs CRUD actions against repository certificate +// resources. +package certificate; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto"; + +// Message to query the server for configured repository certificates +message RepositoryCertificateQuery { + // A file-glob pattern (not regular expression) the host name has to match + string hostNamePattern = 1; + // The type of the certificate to match (ssh or https) + string certType = 2; + // The sub type of the certificate to match (protocol dependent, usually only used for ssh certs) + string certSubType = 3; +} + +// Request to create a set of certificates +message RepositoryCertificateCreateRequest { + // List of certificates to be created + github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.RepositoryCertificateList certificates = 1; + // Whether to upsert already existing certificates + bool upsert = 2; +} + +message RepositoryCertificateResponse {} + +service CertificateService { + // List all available certificates + rpc List(RepositoryCertificateQuery) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.RepositoryCertificateList) { + option (google.api.http).get = "/api/v1/certificates"; + } + + // Creates the requested certificates on the server + rpc Create(RepositoryCertificateCreateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.RepositoryCertificateList) { + option (google.api.http) = { + post: "/api/v1/certificates" + body: "certificates" + }; + } + + rpc Delete(RepositoryCertificateQuery) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.RepositoryCertificateList) { + option (google.api.http).delete = "/api/v1/certificates"; + } +} \ No newline at end of file diff --git a/server/project/project_test.go b/server/project/project_test.go index b37bb19ec1165..d7dcd3d063ebc 100644 --- a/server/project/project_test.go +++ b/server/project/project_test.go @@ -31,7 +31,13 @@ const testNamespace = "default" func TestProjectServer(t *testing.T) { kubeclientset := fake.NewSimpleClientset(&corev1.ConfigMap{ - ObjectMeta: v1.ObjectMeta{Namespace: testNamespace, Name: "argocd-cm"}, + ObjectMeta: v1.ObjectMeta{ + Namespace: testNamespace, + Name: "argocd-cm", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, }, &corev1.Secret{ ObjectMeta: v1.ObjectMeta{ Name: "argocd-secret", diff --git a/server/rbacpolicy/rbacpolicy.go b/server/rbacpolicy/rbacpolicy.go index 0d241b9f5228e..41cedb960bf6c 100644 --- a/server/rbacpolicy/rbacpolicy.go +++ b/server/rbacpolicy/rbacpolicy.go @@ -18,6 +18,7 @@ const ( ResourceProjects = "projects" ResourceApplications = "applications" ResourceRepositories = "repositories" + ResourceCertificates = "certificates" ActionGet = "get" ActionCreate = "create" diff --git a/server/repository/repository.go b/server/repository/repository.go index 1bba72cca7cc9..a29880ad11688 100644 --- a/server/repository/repository.go +++ b/server/repository/repository.go @@ -60,7 +60,7 @@ func (s *Server) getConnectionState(ctx context.Context, url string) appsv1.Conn } repo, err := s.db.GetRepository(ctx, url) if err == nil { - err = git.TestRepo(repo.Repo, repo.Username, repo.Password, repo.SSHPrivateKey, repo.InsecureIgnoreHostKey) + err = git.TestRepo(repo.Repo, repo.Username, repo.Password, repo.SSHPrivateKey, repo.Insecure) } if err != nil { connectionState.Status = appsv1.ConnectionStatusFailed @@ -82,7 +82,11 @@ func (s *Server) List(ctx context.Context, q *repositorypkg.RepoQuery) (*appsv1. items := make([]appsv1.Repository, 0) for _, url := range urls { if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, url) { - items = append(items, appsv1.Repository{Repo: url}) + repo, err := s.db.GetRepository(ctx, url) + if err != nil { + return nil, err + } + items = append(items, appsv1.Repository{Repo: url, Insecure: (repo.InsecureIgnoreHostKey || repo.Insecure), Username: repo.Username}) } } err = util.RunAllAsync(len(items), func(i int) error { @@ -224,7 +228,7 @@ func (s *Server) Create(ctx context.Context, q *repositorypkg.RepoCreateRequest) return nil, err } r := q.Repo - err := git.TestRepo(r.Repo, r.Username, r.Password, r.SSHPrivateKey, r.InsecureIgnoreHostKey) + err := git.TestRepo(r.Repo, r.Username, r.Password, r.SSHPrivateKey, (r.InsecureIgnoreHostKey || r.Insecure)) if err != nil { return nil, err } @@ -274,3 +278,18 @@ func (s *Server) Delete(ctx context.Context, q *repositorypkg.RepoQuery) (*repos err := s.db.DeleteRepository(ctx, q.Repo) return &repositorypkg.RepoResponse{}, err } + +// ValidateAccess checks whether access to a repository is possible with the +// given URL and credentials. +func (s *Server) ValidateAccess(ctx context.Context, q *repositorypkg.RepoAccessQuery) (*repositorypkg.RepoResponse, error) { + if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceRepositories, rbacpolicy.ActionCreate, q.Repo); err != nil { + return nil, err + } + + err := git.TestRepo(q.Repo, q.Username, q.Password, q.SshPrivateKey, q.Insecure) + if err != nil { + return nil, err + } + + return &repositorypkg.RepoResponse{}, err +} diff --git a/server/repository/repository.proto b/server/repository/repository.proto index 3678ac02d5e7b..360042b0e47be 100644 --- a/server/repository/repository.proto +++ b/server/repository/repository.proto @@ -44,6 +44,20 @@ message RepoQuery { string repo = 1; } +// RepoAccessQuery is a query for checking access to a repo +message RepoAccessQuery { + // The URL to the repo + string repo = 1; + // Username for accessing repo + string username = 2; + // Password for accessing repo + string password = 3; + // Private key data for accessing SSH repository + string sshPrivateKey = 4; + // Whether to skip certificate or host key validation + bool insecure = 5; +} + message RepoResponse {} message RepoCreateRequest { @@ -94,4 +108,12 @@ service RepositoryService { option (google.api.http).delete = "/api/v1/repositories/{repo}"; } + // ValidateAccess validates access to a repository with given parameters + rpc ValidateAccess(RepoAccessQuery) returns (RepoResponse) { + option (google.api.http) = { + post: "/api/v1/repositories/{repo}/validate" + body: "repo" + }; + } + } diff --git a/server/server.go b/server/server.go index 44516aaac5186..376e6834809f4 100644 --- a/server/server.go +++ b/server/server.go @@ -47,6 +47,7 @@ import ( "github.com/argoproj/argo-cd/pkg/apiclient" accountpkg "github.com/argoproj/argo-cd/pkg/apiclient/account" applicationpkg "github.com/argoproj/argo-cd/pkg/apiclient/application" + certificatepkg "github.com/argoproj/argo-cd/pkg/apiclient/certificate" clusterpkg "github.com/argoproj/argo-cd/pkg/apiclient/cluster" projectpkg "github.com/argoproj/argo-cd/pkg/apiclient/project" repositorypkg "github.com/argoproj/argo-cd/pkg/apiclient/repository" @@ -60,6 +61,7 @@ import ( "github.com/argoproj/argo-cd/server/account" "github.com/argoproj/argo-cd/server/application" "github.com/argoproj/argo-cd/server/badge" + "github.com/argoproj/argo-cd/server/certificate" "github.com/argoproj/argo-cd/server/cluster" "github.com/argoproj/argo-cd/server/project" "github.com/argoproj/argo-cd/server/rbacpolicy" @@ -454,6 +456,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server { projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock, a.sessionMgr) settingsService := settings.NewServer(a.settingsMgr) accountService := account.NewServer(a.sessionMgr, a.settingsMgr) + certificateService := certificate.NewServer(a.RepoClientset, db, a.enf, a.Cache) versionpkg.RegisterVersionServiceServer(grpcS, &version.Server{}) clusterpkg.RegisterClusterServiceServer(grpcS, clusterService) applicationpkg.RegisterApplicationServiceServer(grpcS, applicationService) @@ -462,6 +465,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server { settingspkg.RegisterSettingsServiceServer(grpcS, settingsService) projectpkg.RegisterProjectServiceServer(grpcS, projectService) accountpkg.RegisterAccountServiceServer(grpcS, accountService) + certificatepkg.RegisterCertificateServiceServer(grpcS, certificateService) // Register reflection service on gRPC server. reflection.Register(grpcS) grpc_prometheus.Register(grpcS) @@ -538,6 +542,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl mustRegisterGWHandler(sessionpkg.RegisterSessionServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts) mustRegisterGWHandler(settingspkg.RegisterSettingsServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts) mustRegisterGWHandler(projectpkg.RegisterProjectServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts) + mustRegisterGWHandler(certificatepkg.RegisterCertificateServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts) // Swagger UI swagger.ServeSwaggerUI(mux, assets.SwaggerJSON, "/swagger-ui") diff --git a/test/certificates/cert1.pem b/test/certificates/cert1.pem new file mode 100644 index 0000000000000..3959a3f3d918c --- /dev/null +++ b/test/certificates/cert1.pem @@ -0,0 +1,33 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/test/certificates/cert2.pem b/test/certificates/cert2.pem new file mode 100644 index 0000000000000..ae615e850b578 --- /dev/null +++ b/test/certificates/cert2.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +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 +XWyb96wrUlv+E8I= +-----END CERTIFICATE----- diff --git a/test/certificates/ssh_known_hosts b/test/certificates/ssh_known_hosts new file mode 100644 index 0000000000000..31a7bae3fce5d --- /dev/null +++ b/test/certificates/ssh_known_hosts @@ -0,0 +1,8 @@ +# This file was automatically generated. DO NOT EDIT +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= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +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 diff --git a/test/testdata.go b/test/testdata.go index a4511b90a1509..bd6cce22363af 100644 --- a/test/testdata.go +++ b/test/testdata.go @@ -198,6 +198,9 @@ func NewFakeConfigMap() *apiv1.ConfigMap { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: FakeArgoCDNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: make(map[string]string), } diff --git a/util/cert/cert.go b/util/cert/cert.go new file mode 100644 index 0000000000000..b32e3b0bd1db2 --- /dev/null +++ b/util/cert/cert.go @@ -0,0 +1,273 @@ +// Utility functions for managing HTTPS server certificates and SSH known host +// entries for ArgoCD +package cert + +import ( + "bufio" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/pem" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "golang.org/x/crypto/ssh" +) + +// A struct representing an entry in the list of SSH known hosts. +type SSHKnownHostsEntry struct { + // Hostname the key is for + Host string + // The type of the key + SubType string + // The data of the key, including the type + Data string + // The SHA256 fingerprint of the key + Fingerprint string +} + +// A representation of a TLS certificate +type TLSCertificate struct { + // Subject of the certificate + Subject string + // Issuer of the certificate + Issuer string + // Certificate data + Data string +} + +// Helper struct for certificate selection +type CertificateListSelector struct { + // Pattern to match the hostname with + HostNamePattern string + // Type of certificate to match + CertType string + // Subtype of certificate to match + CertSubType string +} + +const ( + // Text marker indicating start of certificate in PEM format + CertificateBeginMarker = "-----BEGIN CERTIFICATE-----" + // Text marker indicating end of certificate in PEM format + CertificateEndMarker = "-----END CERTIFICATE-----" + // Maximum number of lines for a single certificate + CertificateMaxLines = 128 + // Maximum number of certificates or known host entries in a stream + CertificateMaxEntriesPerStream = 256 + // Local path where certificate data is stored + CertificateDataPath = "/app/config/tls" +) + +// Decode a certificate in PEM format to X509 data structure +func DecodePEMCertificateToX509(pemData string) (*x509.Certificate, error) { + decodedData, _ := pem.Decode([]byte(pemData)) + if decodedData == nil { + return nil, errors.New("Could not decode PEM data from input.") + } + x509Cert, err := x509.ParseCertificate(decodedData.Bytes) + if err != nil { + return nil, errors.New("Could not parse X509 data from input.") + } + return x509Cert, nil +} + +// Parse TLS certificates from a multiline string +func ParseTLSCertificatesFromData(data string) ([]string, error) { + return ParseTLSCertificatesFromStream(strings.NewReader(data)) +} + +// Parse TLS certificates from a file +func ParseTLSCertificatesFromPath(sourceFile string) ([]string, error) { + fileHandle, err := os.Open(sourceFile) + if err != nil { + return nil, err + } + defer fileHandle.Close() + return ParseTLSCertificatesFromStream(fileHandle) +} + +// Parse TLS certificate data from a data stream. The stream may contain more +// than one certificate. Each found certificate will generate a unique entry +// in the returned slice, so the length of the slice indicates how many +// certificates have been found. +func ParseTLSCertificatesFromStream(stream io.Reader) ([]string, error) { + scanner := bufio.NewScanner(stream) + inCertData := false + pemData := "" + curLine := 0 + certLine := 0 + + certificateList := make([]string, 0) + + // TODO: Implement maximum amount of data to parse + // TODO: Implement error heuristics + + for scanner.Scan() { + curLine += 1 + if !inCertData { + if strings.HasPrefix(scanner.Text(), CertificateBeginMarker) { + certLine = 1 + inCertData = true + pemData += scanner.Text() + "\n" + } + } else { + certLine += 1 + pemData += scanner.Text() + "\n" + if strings.HasPrefix(scanner.Text(), CertificateEndMarker) { + inCertData = false + certificateList = append(certificateList, pemData) + pemData = "" + } + } + + if certLine > CertificateMaxLines { + return nil, errors.New("Maximum number of lines exceeded during certificate parsing.") + } + } + + return certificateList, nil +} + +// Parse TLS certificates from a multiline string +func ParseSSHKnownHostsFromData(data string) ([]string, error) { + return ParseSSHKnownHostsFromStream(strings.NewReader(data)) +} + +func ParseSSHKnownHostsFromPath(sourceFile string) ([]string, error) { + fileHandle, err := os.Open(sourceFile) + if err != nil { + return nil, err + } + defer fileHandle.Close() + return ParseSSHKnownHostsFromStream(fileHandle) +} + +// Parses a list of strings in SSH's known host data format from a stream and +// returns the valid entries in an array. +func ParseSSHKnownHostsFromStream(stream io.Reader) ([]string, error) { + scanner := bufio.NewScanner(stream) + knownHostsLists := make([]string, 0) + curLine := 0 + numEntries := 0 + + for scanner.Scan() { + curLine += 1 + lineData := scanner.Text() + if IsValidSSHKnownHostsEntry(lineData) { + numEntries += 1 + knownHostsLists = append(knownHostsLists, lineData) + } + } + + return knownHostsLists, nil +} + +// Checks whether we can use a line from ssh_known_hosts data as an actual data +// source for a RepoCertificate object. This function only checks for syntactic +// validity, not if the data in the line is valid. +func IsValidSSHKnownHostsEntry(line string) bool { + trimmedEntry := strings.TrimSpace(line) + // We ignore commented out lines - usually happens when copy and pasting + // to the ConfigMap from a known_hosts file or from ssh-keyscan output. + if len(trimmedEntry) == 0 || trimmedEntry[0] == '#' { + return false + } + + // Each line should consist of three fields: host, type, data + keyData := strings.SplitN(trimmedEntry, " ", 3) + return len(keyData) == 3 +} + +// Tokenize a known_hosts entry into hostname, key sub type and actual key data +func TokenizeSSHKnownHostsEntry(knownHostsEntry string) (string, string, []byte, error) { + knownHostsToken := strings.SplitN(knownHostsEntry, " ", 3) + if len(knownHostsToken) != 3 { + return "", "", nil, fmt.Errorf("Error while tokenizing input data.") + } + return knownHostsToken[0], knownHostsToken[1], []byte(knownHostsToken[2]), nil +} + +// Parse a raw known hosts line into a PublicKey object and a list of hosts the +// key would be valid for. +func KnownHostsLineToPublicKey(line string) ([]string, ssh.PublicKey, error) { + _, hostnames, keyData, _, _, err := ssh.ParseKnownHosts([]byte(line)) + if err != nil { + return nil, nil, err + } + return hostnames, keyData, nil +} + +func TokenizedDataToPublicKey(hostname string, subType string, rawKeyData string) ([]string, ssh.PublicKey, error) { + hostnames, keyData, err := KnownHostsLineToPublicKey(fmt.Sprintf("%s %s %s", hostname, subType, rawKeyData)) + if err != nil { + return nil, nil, err + } + return hostnames, keyData, nil +} + +// We do not use full fledged regular expression for matching the hostname. +// Instead, we use a less expensive file system glob, which should be fully +// sufficient for our use case. +func MatchHostName(hostname, pattern string) bool { + // If pattern is empty, we always return a match + if pattern == "" { + return true + } + match, err := filepath.Match(pattern, hostname) + if err != nil { + return false + } + return match +} + +// base64 sha256 hash with the trailing equal sign removed +func SSHFingerprintSHA256(key ssh.PublicKey) string { + hash := sha256.Sum256(key.Marshal()) + b64hash := base64.StdEncoding.EncodeToString(hash[:]) + return strings.TrimRight(b64hash, "=") +} + +// Load certificate data from a file. If the file does not exist, we do not +// consider it an error and just return empty data. +func GetCertificateForConnect(serverName string) ([]string, error) { + certPath := fmt.Sprintf("%s/%s", CertificateDataPath, serverName) + certificates, err := ParseTLSCertificatesFromPath(certPath) + if err != nil { + if os.IsNotExist(err) { + return nil, nil + } else { + return nil, err + } + } + + if len(certificates) == 0 { + return nil, fmt.Errorf("No certificates found in existing file.") + } + + return certificates, nil +} + +func GetCertBundlePathForRepository(serverName string) (string, error) { + certPath := fmt.Sprintf("%s/%s", CertificateDataPath, serverName) + certs, err := GetCertificateForConnect(serverName) + if err != nil { + return "", nil + } + if len(certs) == 0 { + return "", nil + } + return certPath, nil +} + +func GetCertPoolFromPEMData(pemData []string) *x509.CertPool { + certPool := x509.NewCertPool() + for _, pem := range pemData { + certPool.AppendCertsFromPEM([]byte(pem)) + } + return certPool +} diff --git a/util/cert/cert_test.go b/util/cert/cert_test.go new file mode 100644 index 0000000000000..f116ff65d2c9d --- /dev/null +++ b/util/cert/cert_test.go @@ -0,0 +1,337 @@ +package cert + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +const Test_Cert1CN = "CN=foo.example.com,OU=SpecOps,O=Capone\\, Inc,L=Chicago,ST=IL,C=US" +const Test_Cert2CN = "CN=bar.example.com,OU=Testsuite,O=Testing Corp,L=Hanover,ST=Lower Saxony,C=DE" +const Test_TLSValidSingleCert = ` +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- +` + +const Test_TLSInvalidPEMData = ` +MIIF1zCCA7+gAwIBAgIUQdTcSHY2Sxd3Tq/v1eIEZPCNbOowDQYJKoZIhvcNAQEL +BQAwezELMAkGA1UEBhMCREUxFTATBgNVBAgMDExvd2VyIFNheG9ueTEQMA4GA1UE +BwwHSGFub3ZlcjEVMBMGA1UECgwMVGVzdGluZyBDb3JwMRIwEAYDVQQLDAlUZXN0 +c3VpdGUxGDAWBgNVBAMMD2Jhci5leGFtcGxlLmNvbTAeFw0xOTA3MDgxMzU2MTda +Fw0yMDA3MDcxMzU2MTdaMHsxCzAJBgNVBAYTAkRFMRUwEwYDVQQIDAxMb3dlciBT +YXhvbnkxEDAOBgNVBAcMB0hhbm92ZXIxFTATBgNVBAoMDFRlc3RpbmcgQ29ycDES +MBAGA1UECwwJVGVzdHN1aXRlMRgwFgYDVQQDDA9iYXIuZXhhbXBsZS5jb20wggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCv4mHMdVUcafmaSHVpUM0zZWp5 +NFXfboxA4inuOkE8kZlbGSe7wiG9WqLirdr39Ts+WSAFA6oANvbzlu3JrEQ2CHPc +CNQm6diPREFwcDPFCe/eMawbwkQAPVSHPts0UoRxnpZox5pn69ghncBR+jtvx+/u +P6HdwW0qqTvfJnfAF1hBJ4oIk2AXiip5kkIznsAh9W6WRy6nTVCeetmIepDOGe0G +ZJIRn/OfSz7NzKylfDCat2z3EAutyeT/5oXZoWOmGg/8T7pn/pR588GoYYKRQnp+ +YilqCPFX+az09EqqK/iHXnkdZ/Z2fCuU+9M/Zhrnlwlygl3RuVBI6xhm/ZsXtL2E +Gxa61lNy6pyx5+hSxHEFEJshXLtioRd702VdLKxEOuYSXKeJDs1x9o6cJ75S6hko +` + +const Test_TLSInvalidSingleCert = ` +-----BEGIN CERTIFICATE----- +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 +XWyb96wrUlv+E8I= +-----END CERTIFICATE----- +` + +const Test_TLSValidMultiCert = ` +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +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 +XWyb96wrUlv+E8I= +-----END CERTIFICATE----- +` + +// Taken from hack/ssh_known_hosts +const Test_ValidSSHKnownHostsData = ` +# BitBucket +bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== +# GitHub +github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== +# GitLab +gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 +# Azure +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 +` + +const Test_InvalidSSHKnownHostsData = ` +bitbucket.org AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== +# GitHub +github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== +# GitLab +gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 +# Azure +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 +` + +func Test_TLSCertificate_ValidPEM_ValidCert(t *testing.T) { + // Valid PEM data, single certificate, expect array of length 1 + certificates, err := ParseTLSCertificatesFromData(Test_TLSValidSingleCert) + assert.Nil(t, err) + assert.Equal(t, len(certificates), 1) + // Expect good decode + x509Cert, err := DecodePEMCertificateToX509(certificates[0]) + assert.Nil(t, err) + assert.Equal(t, x509Cert.Subject.String(), Test_Cert1CN) +} + +func Test_TLSCertificate_ValidPEM_InvalidCert(t *testing.T) { + // Valid PEM data, but invalid certificate + certificates, err := ParseTLSCertificatesFromData(Test_TLSInvalidSingleCert) + assert.Nil(t, err) + assert.Equal(t, len(certificates), 1) + // Expect bad decode + _, err = DecodePEMCertificateToX509(certificates[0]) + assert.NotNil(t, err) +} + +func Test_TLSCertificate_InvalidPEM(t *testing.T) { + // Invalid PEM data, expect array of length 0 + certificates, err := ParseTLSCertificatesFromData(Test_TLSInvalidPEMData) + assert.Nil(t, err) + assert.Equal(t, len(certificates), 0) +} + +func Test_TLSCertificate_ValidPEM_ValidCert_Multi(t *testing.T) { + // Valid PEM data, two certificates, expect array of length 2 + certificates, err := ParseTLSCertificatesFromData(Test_TLSValidMultiCert) + assert.Nil(t, err) + assert.Equal(t, len(certificates), 2) + // Expect good decode + x509Cert, err := DecodePEMCertificateToX509(certificates[0]) + assert.Nil(t, err) + assert.Equal(t, x509Cert.Subject.String(), Test_Cert1CN) + x509Cert, err = DecodePEMCertificateToX509(certificates[1]) + assert.Nil(t, err) + assert.Equal(t, x509Cert.Subject.String(), Test_Cert2CN) +} + +func Test_TLSCertificate_ValidPEM_ValidCert_FromFile(t *testing.T) { + // Valid PEM data, single certificate from file, expect array of length 1 + certificates, err := ParseTLSCertificatesFromPath("../../test/certificates/cert1.pem") + assert.Nil(t, err) + assert.Equal(t, len(certificates), 1) + // Expect good decode + x509Cert, err := DecodePEMCertificateToX509(certificates[0]) + assert.Nil(t, err) + assert.Equal(t, x509Cert.Subject.String(), Test_Cert1CN) +} + +func Test_TLSCertPool(t *testing.T) { + certificates, err := ParseTLSCertificatesFromData(Test_TLSValidMultiCert) + assert.Nil(t, err) + assert.Equal(t, len(certificates), 2) + certPool := GetCertPoolFromPEMData(certificates) + assert.NotNil(t, certPool) +} + +func Test_TLSCertificate_CertFromNonExistingFile(t *testing.T) { + // Non-existing file, expect err + _, err := ParseTLSCertificatesFromPath("../../test/certificates/cert_nonexisting.pem") + assert.NotNil(t, err) +} + +func Test_SSHKnownHostsData_ParseData(t *testing.T) { + // Expect valid data with 7 known host entries + entries, err := ParseSSHKnownHostsFromData(Test_ValidSSHKnownHostsData) + assert.Nil(t, err) + assert.Equal(t, len(entries), 7) +} + +func Test_SSHKnownHostsData_ParseFile(t *testing.T) { + // Expect valid data with 7 known host entries + entries, err := ParseSSHKnownHostsFromPath("../../test/certificates/ssh_known_hosts") + assert.Nil(t, err) + assert.Equal(t, len(entries), 7) +} + +func Test_SSHKnownHostsData_ParseNonExistingFile(t *testing.T) { + // Expect valid data with 7 known host entries + entries, err := ParseSSHKnownHostsFromPath("../../test/certificates/ssh_known_hosts_invalid") + assert.NotNil(t, err) + assert.Nil(t, entries) +} + +func Test_SSHKnownHostsData_Tokenize(t *testing.T) { + // All entries should parse to valid SSH public keys + // All entries should be tokenizable, and tokens should be feedable to decoder + entries, err := ParseSSHKnownHostsFromData(Test_ValidSSHKnownHostsData) + assert.Nil(t, err) + for _, entry := range entries { + hosts, _, err := KnownHostsLineToPublicKey(entry) + assert.Nil(t, err) + assert.Equal(t, len(hosts), 1) + hoststring, subtype, certdata, err := TokenizeSSHKnownHostsEntry(entry) + assert.Nil(t, err) + hosts, _, err = TokenizedDataToPublicKey(hoststring, subtype, string(certdata)) + assert.Nil(t, err) + assert.Equal(t, len(hosts), 1) + } +} + +func Test_MatchHostName(t *testing.T) { + matchHostName := "foo.example.com" + assert.Equal(t, MatchHostName(matchHostName, "*"), true) + assert.Equal(t, MatchHostName(matchHostName, "*.example.com"), true) + assert.Equal(t, MatchHostName(matchHostName, "foo.*"), true) + assert.Equal(t, MatchHostName(matchHostName, "foo.*.com"), true) + assert.Equal(t, MatchHostName(matchHostName, "fo?.example.com"), true) + assert.Equal(t, MatchHostName(matchHostName, "foo?.example.com"), false) + assert.Equal(t, MatchHostName(matchHostName, "bar.example.com"), false) + assert.Equal(t, MatchHostName(matchHostName, "*.otherexample.com"), false) + assert.Equal(t, MatchHostName(matchHostName, "foo.otherexample.*"), false) +} + +func Test_SSHFingerprintSHA256(t *testing.T) { + // actual SHA256 fingerprints for keys defined above + fingerprints := [...]string{ + "zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1A", + "nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8", + "HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw", + "eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8", + "ROQFvPThGrW4RuWLoL9tq9I9zJ42fK4XywyRtbOz/EQ", + "ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og", + "ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og", + } + entries, err := ParseSSHKnownHostsFromData(Test_ValidSSHKnownHostsData) + assert.Nil(t, err) + assert.Equal(t, len(entries), 7) + for idx, entry := range entries { + _, pubKey, err := KnownHostsLineToPublicKey(entry) + assert.Nil(t, err) + fp := SSHFingerprintSHA256(pubKey) + assert.Equal(t, fp, fingerprints[idx]) + } +} diff --git a/util/db/certificate.go b/util/db/certificate.go new file mode 100644 index 0000000000000..e9f2fc3ab91d1 --- /dev/null +++ b/util/db/certificate.go @@ -0,0 +1,453 @@ +package db + +import ( + "fmt" + + "golang.org/x/crypto/ssh" + "golang.org/x/net/context" + + "github.com/argoproj/argo-cd/common" + appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1" + certutil "github.com/argoproj/argo-cd/util/cert" +) + +// A struct representing an entry in the list of SSH known hosts. +type SSHKnownHostsEntry struct { + // Hostname the key is for + Host string + // The type of the key + SubType string + // The data of the key, including the type + Data string + // The SHA256 fingerprint of the key + Fingerprint string +} + +// A representation of a TLS certificate +type TLSCertificate struct { + // Subject of the certificate + Subject string + // Issuer of the certificate + Issuer string + // Certificate data + Data string +} + +// Helper struct for certificate selection +type CertificateListSelector struct { + // Pattern to match the hostname with + HostNamePattern string + // Type of certificate to match + CertType string + // Subtype of certificate to match + CertSubType string +} + +// Get a list of all configured repository certificates matching the given +// selector. +func (db *db) ListRepoCertificates(ctx context.Context, selector *CertificateListSelector) (*appsv1.RepositoryCertificateList, error) { + + // selector may be given as nil, but we need at least an empty data structure + // so we create it if necessary. + if selector == nil { + selector = &CertificateListSelector{} + } + + certificates := make([]appsv1.RepositoryCertificate, 0) + + // Get all SSH known host entries + if selector.CertType == "" || selector.CertType == "*" || selector.CertType == "ssh" { + sshKnownHosts, err := db.getSSHKnownHostsData() + if err != nil { + return nil, err + } + + for _, entry := range sshKnownHosts { + if certutil.MatchHostName(entry.Host, selector.HostNamePattern) && (selector.CertSubType == "" || selector.CertSubType == "*" || selector.CertSubType == entry.SubType) { + certificates = append(certificates, appsv1.RepositoryCertificate{ + ServerName: entry.Host, + CertType: "ssh", + CertSubType: entry.SubType, + CertData: []byte(entry.Data), + CertFingerprint: entry.Fingerprint, + }) + } + } + } + + // Get all TLS certificates + if selector.CertType == "" || selector.CertType == "*" || selector.CertType == "https" || selector.CertType == "tls" { + tlsCertificates, err := db.getTLSCertificateData() + if err != nil { + return nil, err + } + for _, entry := range tlsCertificates { + if certutil.MatchHostName(entry.Subject, selector.HostNamePattern) { + pemEntries, err := certutil.ParseTLSCertificatesFromData(entry.Data) + if err != nil { + continue + } + for _, pemEntry := range pemEntries { + certificates = append(certificates, appsv1.RepositoryCertificate{ + ServerName: entry.Subject, + CertType: "https", + CertData: []byte(pemEntry), + }) + } + } + } + } + + return &appsv1.RepositoryCertificateList{ + Items: certificates, + }, nil +} + +// Get a single certificate from the datastore +func (db *db) GetRepoCertificate(ctx context.Context, serverType string, serverName string) (*appsv1.RepositoryCertificate, error) { + if serverType == "ssh" { + sshKnownHostsList, err := db.getSSHKnownHostsData() + if err != nil { + return nil, err + } + for _, entry := range sshKnownHostsList { + if entry.Host == serverName { + repo := &appsv1.RepositoryCertificate{ + ServerName: entry.Host, + CertType: "ssh", + CertSubType: entry.SubType, + CertData: []byte(entry.Data), + CertFingerprint: entry.Fingerprint, + } + return repo, nil + } + } + } + + // Fail + return nil, nil +} + +// Create one or more repository certificates and returns a list of certificates +// actually created. +func (db *db) CreateRepoCertificate(ctx context.Context, certificates *appsv1.RepositoryCertificateList, upsert bool) (*appsv1.RepositoryCertificateList, error) { + var ( + saveSSHData bool = false + saveTLSData bool = false + ) + + sshKnownHostsList, err := db.getSSHKnownHostsData() + if err != nil { + return nil, err + } + + tlsCertificates, err := db.getTLSCertificateData() + if err != nil { + return nil, err + } + + // This will hold the final list of certificates that have been created + created := make([]appsv1.RepositoryCertificate, 0) + + // Each request can contain multiple certificates of different types, so we + // make sure to handle each request accordingly. + for _, certificate := range certificates.Items { + if certificate.CertType == "ssh" { + // Whether we have a new certificate entry + newEntry := true + // Whether we have upserted an existing certificate entry + upserted := false + + // Check whether known hosts entry already exists. Must match hostname + // and the key sub type (e.g. ssh-rsa). It is considered an error if we + // already have a corresponding key and upsert was not specified. + for _, entry := range sshKnownHostsList { + if entry.Host == certificate.ServerName && entry.SubType == certificate.CertSubType { + if !upsert && entry.Data != string(certificate.CertData) { + return nil, fmt.Errorf("Key for '%s' (subtype: '%s') already exist and upsert was not specified.", entry.Host, entry.SubType) + } else { + // Do not add an entry on upsert, but remember if we actual did an + // upsert. + newEntry = false + if entry.Data != string(certificate.CertData) { + entry.Data = string(certificate.CertData) + upserted = true + } + break + } + } + } + + // Make sure that we received a valid public host key by parsing it + _, _, rawKeyData, _, _, err := ssh.ParseKnownHosts([]byte(fmt.Sprintf("%s %s %s", certificate.ServerName, certificate.CertSubType, certificate.CertData))) + if err != nil { + return nil, err + } + + if newEntry { + sshKnownHostsList = append(sshKnownHostsList, &SSHKnownHostsEntry{ + Host: certificate.ServerName, + Data: string(certificate.CertData), + SubType: certificate.CertSubType, + }) + } + + // If we created a new entry, or if we upserted an existing one, we need + // to save the data and notify the consumer about the operation. + if newEntry || upserted { + certificate.CertFingerprint = certutil.SSHFingerprintSHA256(rawKeyData) + created = append(created, certificate) + saveSSHData = true + } + + } else if certificate.CertType == "https" { + var tlsCertificate *TLSCertificate = nil + newEntry := true + upserted := false + pemCreated := make([]string, 0) + + for _, entry := range tlsCertificates { + // We have an entry for this server already. Check for upsert. + if entry.Subject == certificate.ServerName { + newEntry = false + if entry.Data != string(certificate.CertData) { + if !upsert { + return nil, fmt.Errorf("TLS certificate for server '%s' already exist and upsert was not specified.", entry.Subject) + } + } + // Store pointer to this entry for later use. + tlsCertificate = entry + break + } + } + + // Check for validity of data received + pemData, err := certutil.ParseTLSCertificatesFromData(string(certificate.CertData)) + if err != nil { + return nil, err + } + + // We should have at least one valid PEM entry + if len(pemData) == 0 { + return nil, fmt.Errorf("No valid PEM data received.") + } + + // Make sure we have valid X509 certificates in the data + for _, entry := range pemData { + _, err := certutil.DecodePEMCertificateToX509(entry) + if err != nil { + return nil, err + } + pemCreated = append(pemCreated, entry) + } + + // New certificate if pointer to existing cert is nil + if tlsCertificate == nil { + tlsCertificate = &TLSCertificate{ + Subject: certificate.ServerName, + Data: string(certificate.CertData), + } + tlsCertificates = append(tlsCertificates, tlsCertificate) + } else { + // We have made sure the upsert flag was set above. Now just figure out + // again if we have to actually update the data in the existing cert. + if tlsCertificate.Data != string(certificate.CertData) { + tlsCertificate.Data = string(certificate.CertData) + upserted = true + } + } + + if newEntry || upserted { + // We append the certificate for every PEM entry in the request, so the + // caller knows that we processed each single item. + for _, entry := range pemCreated { + created = append(created, appsv1.RepositoryCertificate{ + ServerName: certificate.ServerName, + CertType: "https", + CertData: []byte(entry), + }) + } + saveTLSData = true + } + } else { + // Invalid/unknown certificate type + return nil, fmt.Errorf("Unknown certificate type: %s", certificate.CertType) + } + } + + if saveSSHData { + err = db.settingsMgr.SaveSSHKnownHostsData(ctx, knownHostsDataToStrings(sshKnownHostsList)) + if err != nil { + return nil, err + } + } + + if saveTLSData { + err = db.settingsMgr.SaveTLSCertificateData(ctx, tlsCertificatesToMap(tlsCertificates)) + if err != nil { + return nil, err + } + } + + return &appsv1.RepositoryCertificateList{Items: created}, nil +} + +// Batch remove configured certificates according to the selector query +func (db *db) RemoveRepoCertificates(ctx context.Context, selector *CertificateListSelector) (*appsv1.RepositoryCertificateList, error) { + var ( + knownHostsOld []*SSHKnownHostsEntry + knownHostsNew []*SSHKnownHostsEntry + tlsCertificatesOld []*TLSCertificate + tlsCertificatesNew []*TLSCertificate + err error + ) + + removed := &appsv1.RepositoryCertificateList{ + Items: make([]appsv1.RepositoryCertificate, 0), + } + + if selector.CertType == "" || selector.CertType == "ssh" || selector.CertType == "*" { + knownHostsOld, err = db.getSSHKnownHostsData() + if err != nil { + return nil, err + } + knownHostsNew = make([]*SSHKnownHostsEntry, 0) + + for _, entry := range knownHostsOld { + if matchSSHKnownHostsEntry(entry, selector) { + removed.Items = append(removed.Items, appsv1.RepositoryCertificate{ + ServerName: entry.Host, + CertType: "ssh", + CertSubType: entry.SubType, + CertData: []byte(entry.Data), + }) + } else { + knownHostsNew = append(knownHostsNew, entry) + } + } + } + + if selector.CertType == "" || selector.CertType == "*" || selector.CertType == "https" || selector.CertType == "tls" { + tlsCertificatesOld, err = db.getTLSCertificateData() + if err != nil { + return nil, err + } + tlsCertificatesNew = make([]*TLSCertificate, 0) + for _, entry := range tlsCertificatesOld { + if certutil.MatchHostName(entry.Subject, selector.HostNamePattern) { + // Wrap each PEM certificate into its own RepositoryCertificate object + // so the caller knows what has been removed actually. + // + // The downside of this is, only valid data can be removed from the CM, + // so if the data somehow got corrupted, it can only be removed by + // means of editing the CM directly using e.g. kubectl. + pemCertificates, err := certutil.ParseTLSCertificatesFromData(entry.Data) + if err != nil { + return nil, err + } + if len(pemCertificates) > 0 { + for _, pem := range pemCertificates { + removed.Items = append(removed.Items, appsv1.RepositoryCertificate{ + ServerName: entry.Subject, + CertType: "https", + CertData: []byte(pem), + }) + } + } + } else { + tlsCertificatesNew = append(tlsCertificatesNew, entry) + } + } + } + + if len(knownHostsNew) < len(knownHostsOld) { + err = db.settingsMgr.SaveSSHKnownHostsData(ctx, knownHostsDataToStrings(knownHostsNew)) + if err != nil { + return nil, err + } + } + + if len(tlsCertificatesNew) < len(tlsCertificatesOld) { + err = db.settingsMgr.SaveTLSCertificateData(ctx, tlsCertificatesToMap(tlsCertificatesNew)) + if err != nil { + return nil, err + } + } + + return removed, nil +} + +// Converts list of known hosts data to array of strings, suitable for storing +// in a known_hosts file for SSH. +func knownHostsDataToStrings(knownHostsList []*SSHKnownHostsEntry) []string { + knownHostsData := make([]string, 0) + for _, entry := range knownHostsList { + knownHostsData = append(knownHostsData, fmt.Sprintf("%s %s %s", entry.Host, entry.SubType, entry.Data)) + } + return knownHostsData +} + +// Converts list of TLS certificates to a map whose key will be the certificate +// subject and the data will be a string containing TLS certificate data as PEM +func tlsCertificatesToMap(tlsCertificates []*TLSCertificate) map[string]string { + certMap := make(map[string]string) + for _, entry := range tlsCertificates { + certMap[entry.Subject] = entry.Data + } + return certMap +} + +// Get the TLS certificate data from the config map +func (db *db) getTLSCertificateData() ([]*TLSCertificate, error) { + certificates := make([]*TLSCertificate, 0) + certCM, err := db.settingsMgr.GetNamedConfigMap(common.ArgoCDTLSCertsConfigMapName) + if err != nil { + return nil, err + } + for key, entry := range certCM.Data { + certificates = append(certificates, &TLSCertificate{Subject: key, Data: entry}) + } + + return certificates, nil +} + +// Gets the SSH known host data from ConfigMap and parse it into an array of +// SSHKnownHostEntry structs. +func (db *db) getSSHKnownHostsData() ([]*SSHKnownHostsEntry, error) { + certCM, err := db.settingsMgr.GetNamedConfigMap(common.ArgoCDKnownHostsConfigMapName) + if err != nil { + return nil, err + } + + sshKnownHostsData := certCM.Data["ssh_known_hosts"] + entries := make([]*SSHKnownHostsEntry, 0) + + // ssh_known_hosts data contains one key per line, so we must iterate over + // the whole data to get all keys. + // + // We validate the data found to a certain extent before we accept them as + // entry into our list to be returned. + // + sshKnownHostsEntries, err := certutil.ParseSSHKnownHostsFromData(sshKnownHostsData) + if err != nil { + return nil, err + } + + for _, entry := range sshKnownHostsEntries { + hostname, subType, keyData, err := certutil.TokenizeSSHKnownHostsEntry(entry) + if err != nil { + return nil, err + } + entries = append(entries, &SSHKnownHostsEntry{ + Host: hostname, + SubType: subType, + Data: string(keyData), + }) + } + + return entries, nil +} + +func matchSSHKnownHostsEntry(entry *SSHKnownHostsEntry, selector *CertificateListSelector) bool { + return certutil.MatchHostName(entry.Host, selector.HostNamePattern) && (selector.CertSubType == "" || selector.CertSubType == "*" || selector.CertSubType == entry.SubType) +} diff --git a/util/db/certificate_test.go b/util/db/certificate_test.go new file mode 100644 index 0000000000000..d8dcc0c3d1a9b --- /dev/null +++ b/util/db/certificate_test.go @@ -0,0 +1,736 @@ +package db + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/fake" + + "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/util/settings" +) + +const Test_Cert1CN = "CN=foo.example.com,OU=SpecOps,O=Capone\\, Inc,L=Chicago,ST=IL,C=US" +const Test_Cert2CN = "CN=bar.example.com,OU=Testsuite,O=Testing Corp,L=Hanover,ST=Lower Saxony,C=DE" + +var Test_TLS_Subjects []string = []string{ + "CN=foo.example.com,OU=SpecOps,O=Capone\\, Inc,L=Chicago,ST=IL,C=US", + "CN=bar.example.com,OU=Testsuite,O=Testing Corp,L=Hanover,ST=Lower Saxony,C=DE", +} + +const Test_TLSValidSingleCert = ` +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- +` + +const Test_TLSInvalidPEMData = ` +MIIF1zCCA7+gAwIBAgIUQdTcSHY2Sxd3Tq/v1eIEZPCNbOowDQYJKoZIhvcNAQEL +BQAwezELMAkGA1UEBhMCREUxFTATBgNVBAgMDExvd2VyIFNheG9ueTEQMA4GA1UE +BwwHSGFub3ZlcjEVMBMGA1UECgwMVGVzdGluZyBDb3JwMRIwEAYDVQQLDAlUZXN0 +c3VpdGUxGDAWBgNVBAMMD2Jhci5leGFtcGxlLmNvbTAeFw0xOTA3MDgxMzU2MTda +Fw0yMDA3MDcxMzU2MTdaMHsxCzAJBgNVBAYTAkRFMRUwEwYDVQQIDAxMb3dlciBT +YXhvbnkxEDAOBgNVBAcMB0hhbm92ZXIxFTATBgNVBAoMDFRlc3RpbmcgQ29ycDES +MBAGA1UECwwJVGVzdHN1aXRlMRgwFgYDVQQDDA9iYXIuZXhhbXBsZS5jb20wggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCv4mHMdVUcafmaSHVpUM0zZWp5 +NFXfboxA4inuOkE8kZlbGSe7wiG9WqLirdr39Ts+WSAFA6oANvbzlu3JrEQ2CHPc +CNQm6diPREFwcDPFCe/eMawbwkQAPVSHPts0UoRxnpZox5pn69ghncBR+jtvx+/u +P6HdwW0qqTvfJnfAF1hBJ4oIk2AXiip5kkIznsAh9W6WRy6nTVCeetmIepDOGe0G +ZJIRn/OfSz7NzKylfDCat2z3EAutyeT/5oXZoWOmGg/8T7pn/pR588GoYYKRQnp+ +YilqCPFX+az09EqqK/iHXnkdZ/Z2fCuU+9M/Zhrnlwlygl3RuVBI6xhm/ZsXtL2E +Gxa61lNy6pyx5+hSxHEFEJshXLtioRd702VdLKxEOuYSXKeJDs1x9o6cJ75S6hko +` + +const Test_TLSInvalidSingleCert = ` +-----BEGIN CERTIFICATE----- +MIIF1zCCA7+gAwIBAgIUQdTcSHY2Sxd3Tq/v1eIEZPCNbOowDQYJKoZIhvcNAQEL +BQAwezELMAkGA1UEBhMCREUxFTATBgNVBAgMDExvd2VyIFNheG9ueTEQMA4GA1UE +BwwHSGFub3ZlcjEVMBMGA1UECgwMVGVzdGluZyBDb3JwMRIwEAYDVQQLDAlUZXN0 +c3VpdGUxGDAWBgNVBAMMD2Jhci5leGFtcGxlLmNvbTAeFw0xOTA3MDgxMzU2MTda +Fw0yMDA3MDcxMzU2MTdaMHsxCzAJBgNVBAYTAkRFMRUwEwYDVQQIDAxMb3dlciBT +YXhvbnkxEDAOBgNVBAcMB0hhbm92ZXIxFTATBgNVBAoMDFRlc3RpbmcgQ29ycDES +MBAGA1UECwwJVGVzdHN1aXRlMRgwFgYDVQQDDA9iYXIuZXhhbXBsZS5jb20wggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCv4mHMdVUcafmaSHVpUM0zZWp5 +NFXfboxA4inuOkE8kZlbGSe7wiG9WqLirdr39Ts+WSAFA6oANvbzlu3JrEQ2CHPc +CNQm6diPREFwcDPFCe/eMawbwkQAPVSHPts0UoRxnpZox5pn69ghncBR+jtvx+/u +P6HdwW0qqTvfJnfAF1hBJ4oIk2AXiip5kkIznsAh9W6WRy6nTVCeetmIepDOGe0G +ZJIRn/OfSz7NzKylfDCat2z3EAutyeT/5oXZoWOmGg/8T7pn/pR588GoYYKRQnp+ +YilqCPFX+az09EqqK/iHXnkdZ/Z2fCuU+9M/Zhrnlwlygl3RuVBI6xhm/ZsXtL2E +Gxa61lNy6pyx5+hSxHEFEJshXLtioRd702VdLKxEOuYSXKeJDs1x9o6cJ75S6hko +Ml1L4zCU+xEsMcvb1iQ2n7PZdacqhkFRUVVVmJ56th8aYyX7KNX6M9CD+kMpNm6J +kKC1li/Iy+RI138bAvaFplajMF551kt44dSvIoJIbTr1LigudzWPqk31QaZXV/4u +kD1n4p/XMc9HYU/was/CmQBFqmIZedTLTtK7clkuFN6wbwzdo1wmUNgnySQuMacO +gxhHxxzRWxd24uLyk9Px+9U3BfVPaRLiOPaPoC58lyVOykjSgfpgbus7JS69fCq7 +bEH4Jatp/10zkco+UQIDAQABo1MwUTAdBgNVHQ4EFgQUjXH6PHi92y4C4hQpey86 +r6+x1ewwHwYDVR0jBBgwFoAUjXH6PHi92y4C4hQpey86r6+x1ewwDwYDVR0TAQH/ +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAFE4SdKsX9UsLy+Z0xuHSxhTd0jfn +Iih5mtzb8CDNO5oTw4z0aMeAvpsUvjJ/XjgxnkiRACXh7K9hsG2r+ageRWGevyvx +CaRXFbherV1kTnZw4Y9/pgZTYVWs9jlqFOppz5sStkfjsDQ5lmPJGDii/StENAz2 +XmtiPOgfG9Upb0GAJBCuKnrU9bIcT4L20gd2F4Y14ccyjlf8UiUi192IX6yM9OjT ++TuXwZgqnTOq6piVgr+FTSa24qSvaXb5z/mJDLlk23npecTouLg83TNSn3R6fYQr +d/Y9eXuUJ8U7/qTh2Ulz071AO9KzPOmleYPTx4Xty4xAtWi1QE5NHW9/Ajlv5OtO +OnMNWIs7ssDJBsB7VFC8hcwf79jz7kC0xmQqDfw51Xhhk04kla+v+HZcFW2AO9so +6ZdVHHQnIbJa7yQJKZ+hK49IOoBR6JgdB5kymoplLLiuqZSYTcwSBZ72FYTm3iAr +jzvt1hxpxVDmXvRnkhRrIRhK4QgJL0jRmirBjDY+PYYd7bdRIjN7WNZLFsgplnS8 +9w6CwG32pRlm0c8kkiQ7FXA6BYCqOsDI8f1VGQv331OpR2Ck+FTv+L7DAmg6l37W ++LB9LGh4OAp68ImTjqfoGKG0RBSznwME+r4nXtT1S/qLR6ASWUS4ViWRhbRlNK +XWyb96wrUlv+E8I= +-----END CERTIFICATE----- +` + +const Test_TLSValidMultiCert = ` +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +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 +XWyb96wrUlv+E8I= +-----END CERTIFICATE----- +` + +// Taken from hack/ssh_known_hosts +const Test_ValidSSHKnownHostsData = ` +# BitBucket +bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== +# GitHub +github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== +# GitLab +gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 +# Azure +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 +` + +const Test_InvalidSSHKnownHostsData = ` +bitbucket.org AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== +# GitHub +github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== +# GitLab +gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 +# Azure +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 +` + +var Test_SSH_Hostname_Entries []string = []string{ + "bitbucket.org", + "github.com", + "gitlab.com", + "gitlab.com", + "gitlab.com", + "ssh.dev.azure.com", + "vs-ssh.visualstudio.com", +} + +var Test_SSH_Subtypes []string = []string{ + "ssh-rsa", + "ssh-rsa", + "ecdsa-sha2-nistp256", + "ssh-ed25519", + "ssh-rsa", + "ssh-rsa", + "ssh-rsa", +} + +var Test_TLS_Hostnames []string = []string{ + "test.example.com", + "test.example.com", + "github.com", +} + +const Test_NumSSHKnownHostsExpected = 7 +const Test_NumTLSCertificatesExpected = 3 + +func getCertClientset() *fake.Clientset { + cm := v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-cm", + Namespace: testNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: nil, + } + + sshCM := v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-ssh-known-hosts-cm", + Namespace: testNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string]string{ + "ssh_known_hosts": Test_ValidSSHKnownHostsData, + }, + } + + tlsCM := v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-tls-certs-cm", + Namespace: testNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + Data: map[string]string{ + "test.example.com": Test_TLSValidMultiCert, + "gitlab.com": Test_TLSValidSingleCert, + }, + } + + return fake.NewSimpleClientset([]runtime.Object{&cm, &sshCM, &tlsCM}...) +} + +func Test_ListCertificate(t *testing.T) { + clientset := getCertClientset() + db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) + assert.NotNil(t, db) + + // List all SSH known host entries from configuration. + // Expected: List of 7 entries + certList, err := db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "*", + CertType: "ssh", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, len(certList.Items), Test_NumSSHKnownHostsExpected) + for idx, entry := range certList.Items { + assert.Equal(t, entry.ServerName, Test_SSH_Hostname_Entries[idx]) + assert.Equal(t, entry.CertSubType, Test_SSH_Subtypes[idx]) + } + + // List all TLS certificates from configuration. + // Expected: List of 3 entries + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "*", + CertType: "https", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, len(certList.Items), Test_NumTLSCertificatesExpected) + + // List all certificates using selector + // Expected: List of 10 entries + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "*", + CertType: "*", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, len(certList.Items), Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected) + + // List all certificates using nil selector + // Expected: List of 10 entries + certList, err = db.ListRepoCertificates(context.Background(), nil) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, len(certList.Items), Test_NumTLSCertificatesExpected+Test_NumSSHKnownHostsExpected) + + // List all certificates matching a host name pattern + // Expected: List of 4 entries, all with servername gitlab.com + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "gitlab.com", + CertType: "*", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 4, len(certList.Items)) + for _, entry := range certList.Items { + assert.Equal(t, "gitlab.com", entry.ServerName) + } + + // List all TLS certificates matching a host name pattern + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "gitlab.com", + CertType: "https", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 1, len(certList.Items)) + assert.Equal(t, "gitlab.com", certList.Items[0].ServerName) + assert.Equal(t, "https", certList.Items[0].CertType) +} + +func Test_CreateSSHKnownHostEntries(t *testing.T) { + clientset := getCertClientset() + db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) + assert.NotNil(t, db) + + // Valid known hosts entry + certList, err := db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "foo.example.com", + CertType: "ssh", + CertData: []byte("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDioSMcGxdVkHaQzRjP71nY4mgVHXjuZiYN9NBiUxNZ0DYGjTIENI3uV45XxrS6PQfoyekUlVlHK2jwpcPrqAg6rlAdMD5WIxzvCnFjCuPA6Ljk8p0ZmYbvriDcgtj+UfGEdyUTgxH2gch6KwTY0eAbLue15IuXtoNzpLxk29iGRi5ZXNAbSBjeB3hm2PKLa6LnDqdkvc+nqoYqn1Fvx7ZJIh0apBCJpOtHPON4rnl7QQvNg9pWulZ5GKcpYMRfTpvHyFTEyrsVT5GH38l9s355GqU7GxQ/i6Tj1D0MKrIB2WmdjOnujM/ELLsrkYspMhn8ZRpCphN/LTcrOWsb0AM69drvYlhc6cnNAtC4UXp0GUy1HsBiJCsUm9/1Gz23VLDRvWop8yE8+PE3Ho5eL7ad9wmOG0mSOYEqVvAstmd8vzbD6oRuY8qV8X3tt9ph2tMAve0Qbo0NN3c51c9OfdXtJaSyckjEjaK7zjnArnYfladZZVlf2Tv8FsV0sJmfSAE="), + }, + }, + }, false) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 1, len(certList.Items)) + + // Check if it really was added + // Result: List of 1 entry + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "foo.example.com", + CertType: "ssh", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 1, len(certList.Items)) + + // Existing cert, same data, no upsert + // Result: no error, should return 0 added certificates + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "foo.example.com", + CertType: "ssh", + CertData: []byte("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDioSMcGxdVkHaQzRjP71nY4mgVHXjuZiYN9NBiUxNZ0DYGjTIENI3uV45XxrS6PQfoyekUlVlHK2jwpcPrqAg6rlAdMD5WIxzvCnFjCuPA6Ljk8p0ZmYbvriDcgtj+UfGEdyUTgxH2gch6KwTY0eAbLue15IuXtoNzpLxk29iGRi5ZXNAbSBjeB3hm2PKLa6LnDqdkvc+nqoYqn1Fvx7ZJIh0apBCJpOtHPON4rnl7QQvNg9pWulZ5GKcpYMRfTpvHyFTEyrsVT5GH38l9s355GqU7GxQ/i6Tj1D0MKrIB2WmdjOnujM/ELLsrkYspMhn8ZRpCphN/LTcrOWsb0AM69drvYlhc6cnNAtC4UXp0GUy1HsBiJCsUm9/1Gz23VLDRvWop8yE8+PE3Ho5eL7ad9wmOG0mSOYEqVvAstmd8vzbD6oRuY8qV8X3tt9ph2tMAve0Qbo0NN3c51c9OfdXtJaSyckjEjaK7zjnArnYfladZZVlf2Tv8FsV0sJmfSAE="), + }, + }, + }, false) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 0, len(certList.Items)) + + // Existing cert, different data, no upsert + // Result: Error + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "foo.example.com", + CertType: "ssh", + CertData: []byte("ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ=="), + }, + }, + }, false) + assert.NotNil(t, err) + assert.Nil(t, certList) + + // Existing cert, different data, upsert + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "foo.example.com", + CertType: "ssh", + CertData: []byte("ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ=="), + }, + }, + }, true) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 1, len(certList.Items)) + + // Invalid known hosts entry, case 1: key sub type missing + // Result: Error + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "bar.example.com", + CertType: "ssh", + CertData: []byte("AAAAB3NzaC1yc2EAAAADAQABAAABgQDioSMcGxdVkHaQzRjP71nY4mgVHXjuZiYN9NBiUxNZ0DYGjTIENI3uV45XxrS6PQfoyekUlVlHK2jwpcPrqAg6rlAdMD5WIxzvCnFjCuPA6Ljk8p0ZmYbvriDcgtj+UfGEdyUTgxH2gch6KwTY0eAbLue15IuXtoNzpLxk29iGRi5ZXNAbSBjeB3hm2PKLa6LnDqdkvc+nqoYqn1Fvx7ZJIh0apBCJpOtHPON4rnl7QQvNg9pWulZ5GKcpYMRfTpvHyFTEyrsVT5GH38l9s355GqU7GxQ/i6Tj1D0MKrIB2WmdjOnujM/ELLsrkYspMhn8ZRpCphN/LTcrOWsb0AM69drvYlhc6cnNAtC4UXp0GUy1HsBiJCsUm9/1Gz23VLDRvWop8yE8+PE3Ho5eL7ad9wmOG0mSOYEqVvAstmd8vzbD6oRuY8qV8X3tt9ph2tMAve0Qbo0NN3c51c9OfdXtJaSyckjEjaK7zjnArnYfladZZVlf2Tv8FsV0sJmfSAE="), + }, + }, + }, false) + assert.NotNil(t, err) + assert.Nil(t, certList) + + // Invalid known hosts entry, case 2: invalid base64 data + // Result: Error + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "bar.example.com", + CertType: "ssh", + CertData: []byte("ssh-rsa AAAAB3Nza1yc2EAAAADAQABAAABgQDioSMcGxdVkHaQzRjP71nY4mgVHXjuZiYN9NBiUxNZ0DYGjTIENI3uV45XxrS6PQfoyekUlVlHK2jwpcPrqAg6rlAdMD5WIxzvCnFjCuPA6Ljk8p0ZmYbvriDcgtj+UfGEdyUTgxH2gch6KwTY0eAbLue15IuXtoNzpLxk29iGRi5ZXNAbSBjeB3hm2PKLa6LnDqdkvc+nqoYqn1Fvx7ZJIh0apBCJpOtHPON4rnl7QQvNg9pWulZ5GKcpYMRfTpvHyFTEyrsVT5GH38l9s355GqU7GxQ/i6Tj1D0MKrIB2WmdjOnujM/ELLsrkYspMhn8ZRpCphN/LTcrOWsb0AM69drvYlhc6cnNAtC4UXp0GUy1HsBiJCsUm9/1Gz23VLDRvWop8yE8+PE3Ho5eL7ad9wmOG0mSOYEqVvAstmd8vzbD6oRuY8qV8X3tt9ph2tMAve0Qbo0NN3c51c9OfdXtJaSyckjEjaK7zjnArnYfladZZVlf2Tv8FsV0sJmfSAE="), + }, + }, + }, false) + assert.NotNil(t, err) + assert.Nil(t, certList) +} + +func Test_CreateTLSCertificates(t *testing.T) { + clientset := getCertClientset() + db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) + assert.NotNil(t, db) + + // Valid TLS certificate + // Expected: List of 1 entry + certList, err := db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "foo.example.com", + CertType: "https", + CertData: []byte(Test_TLSValidSingleCert), + }, + }, + }, false) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 1, len(certList.Items)) + + // Check if it really was added + // Result: Return new certificate + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "foo.example.com", + CertType: "https", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 1, len(certList.Items)) + + // Valid TLS certificates, multiple PEMs in data + // Expected: List of 2 entry + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "bar.example.com", + CertType: "https", + CertData: []byte(Test_TLSValidMultiCert), + }, + }, + }, false) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 2, len(certList.Items)) + + // Check if it really was added + // Result: Return new certificate + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "bar.example.com", + CertType: "https", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 2, len(certList.Items)) + + // Valid TLS certificate, existing cert, same data, no upsert + // Expected: List of 0 entry + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "foo.example.com", + CertType: "https", + CertData: []byte(Test_TLSValidSingleCert), + }, + }, + }, false) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 0, len(certList.Items)) + + // Valid TLS certificate, existing cert, different data, no upsert + // Expected: Error + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "foo.example.com", + CertType: "https", + CertData: []byte(Test_TLSValidMultiCert), + }, + }, + }, false) + assert.NotNil(t, err) + assert.Nil(t, certList) + + // Valid TLS certificate, existing cert, different data, upsert + // Expected: List of 2 entries + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "foo.example.com", + CertType: "https", + CertData: []byte(Test_TLSValidMultiCert), + }, + }, + }, true) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 2, len(certList.Items)) + + // Check if upsert was successful + // Expected: List of 2 entries, matching hostnames & cert types + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "foo.example.com", + CertType: "https", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 2, len(certList.Items)) + for _, entry := range certList.Items { + assert.Equal(t, "foo.example.com", entry.ServerName) + assert.Equal(t, "https", entry.CertType) + } + + // Invalid PEM data, new cert + // Expected: Error + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "baz.example.com", + CertType: "https", + CertData: []byte(Test_TLSInvalidPEMData), + }, + }, + }, false) + assert.NotNil(t, err) + assert.Nil(t, certList) + + // Valid PEM data, new cert, but invalid certificate + // Expected: Error + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "baz.example.com", + CertType: "https", + CertData: []byte(Test_TLSInvalidSingleCert), + }, + }, + }, false) + assert.NotNil(t, err) + assert.Nil(t, certList) + + // Invalid PEM data, existing cert, upsert + // Expected: Error + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "baz.example.com", + CertType: "https", + CertData: []byte(Test_TLSInvalidPEMData), + }, + }, + }, true) + assert.NotNil(t, err) + assert.Nil(t, certList) + + // Valid PEM data, existing cert, but invalid certificate, upsert + // Expected: Error + certList, err = db.CreateRepoCertificate(context.Background(), &v1alpha1.RepositoryCertificateList{ + Items: []v1alpha1.RepositoryCertificate{ + { + ServerName: "baz.example.com", + CertType: "https", + CertData: []byte(Test_TLSInvalidSingleCert), + }, + }, + }, true) + assert.NotNil(t, err) + assert.Nil(t, certList) + +} + +func Test_RemoveSSHKnownHosts(t *testing.T) { + clientset := getCertClientset() + db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) + assert.NotNil(t, db) + + // Remove single SSH known hosts entry by hostname + // Expected: List of 1 entry + certList, err := db.RemoveRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "github.com", + CertType: "ssh", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 1, len(certList.Items)) + + // Check whether entry was really removed + // Expected: List of 0 entries + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "github.com", + CertType: "ssh", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 0, len(certList.Items)) + + // Remove single SSH known hosts entry by sub type + // Expected: List of 1 entry + certList, err = db.RemoveRepoCertificates(context.Background(), &CertificateListSelector{ + CertType: "ssh", + CertSubType: "ssh-ed25519", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 1, len(certList.Items)) + + // Check whether entry was really removed + // Expected: List of 0 entries + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + CertType: "ssh", + CertSubType: "ssh-ed25519", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 0, len(certList.Items)) + + // Remove all remaining SSH known hosts entries + // Expected: List of 5 entry + certList, err = db.RemoveRepoCertificates(context.Background(), &CertificateListSelector{ + CertType: "ssh", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 5, len(certList.Items)) + + // Check whether the entries were really removed + // Expected: List of 0 entries + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + CertType: "ssh", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 0, len(certList.Items)) +} + +func Test_RemoveTLSCertificates(t *testing.T) { + clientset := getCertClientset() + db := NewDB(testNamespace, settings.NewSettingsManager(context.Background(), clientset, testNamespace), clientset) + assert.NotNil(t, db) + + // Remove single TLS certificate entry by hostname + // Expected: List of 1 entry + certList, err := db.RemoveRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "gitlab.com", + CertType: "https", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 1, len(certList.Items)) + + // Check whether entry was really removed + // Expected: List of 0 entries + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "gitlab.com", + CertType: "https", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 0, len(certList.Items)) + + // Remove all TLS certificate entry for hostname + // Expected: List of 2 entry + certList, err = db.RemoveRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "test.example.com", + CertType: "https", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 2, len(certList.Items)) + + // Check whether entries were really removed + // Expected: List of 0 entries + certList, err = db.ListRepoCertificates(context.Background(), &CertificateListSelector{ + HostNamePattern: "test.example.com", + CertType: "https", + }) + assert.Nil(t, err) + assert.NotNil(t, certList) + assert.Equal(t, 0, len(certList.Items)) + +} diff --git a/util/db/db.go b/util/db/db.go index c19f24bc146e2..c1e453c1eaf69 100644 --- a/util/db/db.go +++ b/util/db/db.go @@ -37,6 +37,13 @@ type ArgoDB interface { // ListHelmRepoURLs lists configured helm repositories ListHelmRepos(ctx context.Context) ([]*appv1.HelmRepository, error) + + // ListRepoCerticifates lists all configured certificates + ListRepoCertificates(ctx context.Context, selector *CertificateListSelector) (*appv1.RepositoryCertificateList, error) + // CreateRepoCertificate creates a new certificate entry + CreateRepoCertificate(ctx context.Context, certificate *appv1.RepositoryCertificateList, upsert bool) (*appv1.RepositoryCertificateList, error) + // CreateRepoCertificate creates a new certificate entry + RemoveRepoCertificates(ctx context.Context, selector *CertificateListSelector) (*appv1.RepositoryCertificateList, error) } type db struct { diff --git a/util/db/db_test.go b/util/db/db_test.go index deef694e34e63..a4283e6926b6c 100644 --- a/util/db/db_test.go +++ b/util/db/db_test.go @@ -38,6 +38,9 @@ func getClientset(config map[string]string, objects ...runtime.Object) *fake.Cli ObjectMeta: metav1.ObjectMeta{ Name: "argocd-cm", Namespace: testNamespace, + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: config, } diff --git a/util/db/repository.go b/util/db/repository.go index 3c7dc8b6030f0..ad4dfa712d3fd 100644 --- a/util/db/repository.go +++ b/util/db/repository.go @@ -64,7 +64,8 @@ func (db *db) CreateRepository(ctx context.Context, r *appsv1.Repository) (*apps repoInfo := settings.RepoCredentials{ URL: r.Repo, - InsecureIgnoreHostKey: r.InsecureIgnoreHostKey, + InsecureIgnoreHostKey: (r.InsecureIgnoreHostKey || r.Insecure), + Insecure: (r.InsecureIgnoreHostKey || r.Insecure), } err = db.updateSecrets(&repoInfo, r) if err != nil { @@ -121,6 +122,7 @@ func (db *db) credentialsToRepository(repoInfo settings.RepoCredentials) (*appsv repo := &appsv1.Repository{ Repo: repoInfo.URL, InsecureIgnoreHostKey: repoInfo.InsecureIgnoreHostKey, + Insecure: repoInfo.Insecure, } err := db.unmarshalFromSecretsStr(map[*string]*apiv1.SecretKeySelector{ &repo.Username: repoInfo.UsernameSecret, diff --git a/util/git/client.go b/util/git/client.go index 259f746fd76ba..0e30a70d2666a 100644 --- a/util/git/client.go +++ b/util/git/client.go @@ -1,7 +1,10 @@ package git import ( + "crypto/tls" "fmt" + "net/http" + "net/url" "os" "os/exec" "strconv" @@ -15,10 +18,11 @@ import ( "gopkg.in/src-d/go-git.v4/config" "gopkg.in/src-d/go-git.v4/plumbing" "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/plumbing/transport/http" + githttp "gopkg.in/src-d/go-git.v4/plumbing/transport/http" ssh2 "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh" "gopkg.in/src-d/go-git.v4/storage/memory" + certutil "github.com/argoproj/argo-cd/util/cert" argoconfig "github.com/argoproj/argo-cd/util/config" ) @@ -44,14 +48,19 @@ type Client interface { // ClientFactory is a factory of Git Clients // Primarily used to support creation of mock git clients during unit testing type ClientFactory interface { - NewClient(repoURL, path, username, password, sshPrivateKey string, insecureIgnoreHostKey bool) (Client, error) + NewClient(repoURL, path, username, password, sshPrivateKey string, insecure bool) (Client, error) } // nativeGitClient implements Client interface using git CLI type nativeGitClient struct { + // URL of the repository repoURL string - root string - creds Creds + // Root path of repository + root string + // Authenticator credentials for private repositories + creds Creds + // Whether to connect insecurely to repository, e.g. don't verify certificate + insecure bool } type factory struct{} @@ -60,23 +69,90 @@ func NewFactory() ClientFactory { return &factory{} } -func (f *factory) NewClient(rawRepoURL, path, username, password, sshPrivateKey string, insecureIgnoreHostKey bool) (Client, error) { +func (f *factory) NewClient(rawRepoURL, path, username, password, sshPrivateKey string, insecure bool) (Client, error) { var creds Creds if sshPrivateKey != "" { - creds = SSHCreds{sshPrivateKey, insecureIgnoreHostKey} + creds = SSHCreds{sshPrivateKey, insecure} } else if username != "" || password != "" { creds = HTTPSCreds{username, password} } else { creds = NopCreds{} } + + // We need a custom HTTP client for go-git when we want to skip validation + // of the server's TLS certificate (--insecure-ignore-server-cert). Since + // this change is permanent to go-git Client during runtime, we need to + // explicitly replace it with default client for repositories without the + // insecure flag set. + //if IsHTTPSURL(rawRepoURL) { + // gitclient.InstallProtocol("https", githttp.NewClient(getRepoHTTPClient(rawRepoURL, insecure))) + //} client := nativeGitClient{ - repoURL: rawRepoURL, - root: path, - creds: creds, + repoURL: rawRepoURL, + root: path, + creds: creds, + insecure: insecure, } return &client, nil } +// Returns a HTTP client object suitable for go-git to use using the following +// pattern: +// - If insecure is true, always returns a client with certificate verification +// turned off. +// - If one or more custom certificates are stored for the repository, returns +// a client with those certificates in the list of root CAs used to verify +// the server's certificate. +// - Otherwise (and on non-fatal errors), a default HTTP client is returned. +func getRepoHTTPClient(repoURL string, insecure bool) transport.Transport { + // Default HTTP client + var customHTTPClient transport.Transport = githttp.NewClient(&http.Client{}) + + if insecure { + customHTTPClient = githttp.NewClient(&http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, + // 15 second timeout + Timeout: 15 * time.Second, + + // don't follow redirect + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + }) + } else { + parsedURL, err := url.Parse(repoURL) + if err != nil { + return customHTTPClient + } + serverCertificatePem, err := certutil.GetCertificateForConnect(parsedURL.Host) + if err != nil { + return customHTTPClient + } else if len(serverCertificatePem) > 0 { + certPool := certutil.GetCertPoolFromPEMData(serverCertificatePem) + customHTTPClient = githttp.NewClient(&http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: certPool, + }, + }, + // 15 second timeout + Timeout: 15 * time.Second, + // don't follow redirect + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + }) + } + // else no custom certificate stored. + } + + return customHTTPClient +} + func newAuth(repoURL string, creds Creds) (transport.AuthMethod, error) { switch creds := creds.(type) { case SSHCreds: @@ -94,7 +170,7 @@ func newAuth(repoURL string, creds Creds) (transport.AuthMethod, error) { } return auth, nil case HTTPSCreds: - auth := http.BasicAuth{Username: creds.username, Password: creds.password} + auth := githttp.BasicAuth{Username: creds.username, Password: creds.password} return &auth, nil } return nil, nil @@ -188,7 +264,8 @@ func (m *nativeGitClient) LsRemote(revision string) (string, error) { if err != nil { return "", err } - refs, err := remote.List(&git.ListOptions{Auth: auth}) + //refs, err := remote.List(&git.ListOptions{Auth: auth}) + refs, err := listRemote(remote, &git.ListOptions{Auth: auth}, m.insecure) if err != nil { return "", err } @@ -291,11 +368,30 @@ func (m *nativeGitClient) runCredentialedCmd(command string, args ...string) (st } func (m *nativeGitClient) runCmdOutput(cmd *exec.Cmd) (string, error) { - log.Debug(strings.Join(cmd.Args, " ")) cmd.Dir = m.root cmd.Env = append(cmd.Env, os.Environ()...) cmd.Env = append(cmd.Env, "HOME=/dev/null") cmd.Env = append(cmd.Env, "GIT_CONFIG_NOSYSTEM=true") cmd.Env = append(cmd.Env, "GIT_CONFIG_NOGLOBAL=true") + // For HTTPS repositories, we need to consider insecure repositories as well + // as custom CA bundles from the cert database. + if IsHTTPSURL(m.repoURL) { + if m.insecure { + cmd.Env = append(cmd.Env, "GIT_SSL_NO_VERIFY=true") + } else { + parsedURL, err := url.Parse(m.repoURL) + // We don't fail if we cannot parse the URL, but log a warning in that + // case. And we execute the command in a verbatim way. + if err != nil { + log.Warnf("runCmdOutput: Could not parse repo URL '%s'", m.repoURL) + } else { + caPath, err := certutil.GetCertBundlePathForRepository(parsedURL.Host) + if err == nil && caPath != "" { + cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_SSL_CAINFO=%s", caPath)) + } + } + } + } + log.Debug(strings.Join(cmd.Args, " ")) return argoexec.RunCommandExt(cmd, argoconfig.CmdOpts()) } diff --git a/util/git/git.go b/util/git/git.go index 94092fb07341e..36cbe9a22be53 100644 --- a/util/git/git.go +++ b/util/git/git.go @@ -25,6 +25,7 @@ func removeSuffix(s, suffix string) string { var ( commitSHARegex = regexp.MustCompile("^[0-9A-Fa-f]{40}$") sshURLRegex = regexp.MustCompile("^(ssh://)?([^/@:]*?)@.*") + httpsURLRegex = regexp.MustCompile("^(https://).*") ) // IsCommitSHA returns whether or not a string is a 40 character SHA-1 @@ -71,6 +72,11 @@ func IsSSHURL(url string) (bool, string) { return false, "" } +// IsHTTPSURL returns true if supplied URL is HTTPS URL +func IsHTTPSURL(url string) bool { + return httpsURLRegex.MatchString(url) +} + // TestRepo tests if a repo exists and is accessible with the given credentials func TestRepo(repo, username, password string, sshPrivateKey string, insecureIgnoreHostKey bool) error { clnt, err := NewFactory().NewClient(repo, "", username, password, sshPrivateKey, insecureIgnoreHostKey) diff --git a/util/git/workaround.go b/util/git/workaround.go new file mode 100644 index 0000000000000..1117b13773233 --- /dev/null +++ b/util/git/workaround.go @@ -0,0 +1,74 @@ +package git + +import ( + "gopkg.in/src-d/go-git.v4" + "gopkg.in/src-d/go-git.v4/plumbing" + "gopkg.in/src-d/go-git.v4/plumbing/transport" + "gopkg.in/src-d/go-git.v4/plumbing/transport/client" + "gopkg.in/src-d/go-git.v4/utils/ioutil" +) + +// Below is a workaround for https://github.com/src-d/go-git/issues/1177: the `github.com/src-d/go-git` does not support disable SSL cert verification is a single repo. +// As workaround methods `newUploadPackSession`, `newClient` and `listRemote` were copied from https://github.com/src-d/go-git/blob/master/remote.go and modified to use +// transport with InsecureSkipVerify flag is verification should be disabled. + +func newUploadPackSession(url string, auth transport.AuthMethod, insecureSkipTLSVerify bool) (transport.UploadPackSession, error) { + c, ep, err := newClient(url, insecureSkipTLSVerify) + if err != nil { + return nil, err + } + + return c.NewUploadPackSession(ep, auth) +} + +func newClient(url string, insecureSkipTLSVerify bool) (transport.Transport, *transport.Endpoint, error) { + ep, err := transport.NewEndpoint(url) + if err != nil { + return nil, nil, err + } + + var c transport.Transport + // For HTTPS repositories, we get a custom Transport. Everything else will + // be default. + if IsHTTPSURL(url) { + c = getRepoHTTPClient(url, insecureSkipTLSVerify) + } else { + c, err = client.NewClient(ep) + if err != nil { + return nil, nil, err + } + } + return c, ep, err +} + +func listRemote(r *git.Remote, o *git.ListOptions, insecureSkipTLSVerify bool) (rfs []*plumbing.Reference, err error) { + s, err := newUploadPackSession(r.Config().URLs[0], o.Auth, insecureSkipTLSVerify) + if err != nil { + return nil, err + } + + defer ioutil.CheckClose(s, &err) + + ar, err := s.AdvertisedReferences() + if err != nil { + return nil, err + } + + allRefs, err := ar.AllReferences() + if err != nil { + return nil, err + } + + refs, err := allRefs.IterReferences() + if err != nil { + return nil, err + } + + var resultRefs []*plumbing.Reference + _ = refs.ForEach(func(ref *plumbing.Reference) error { + resultRefs = append(resultRefs, ref) + return nil + }) + + return resultRefs, nil +} diff --git a/util/session/sessionmanager_test.go b/util/session/sessionmanager_test.go index d755f5e6fc2e1..83aad01550219 100644 --- a/util/session/sessionmanager_test.go +++ b/util/session/sessionmanager_test.go @@ -27,6 +27,9 @@ func TestSessionManager(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "argocd-cm", Namespace: "argocd", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, }, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ diff --git a/util/settings/settings.go b/util/settings/settings.go index d387be3a50299..647a2536823fe 100644 --- a/util/settings/settings.go +++ b/util/settings/settings.go @@ -80,12 +80,20 @@ type OIDCConfig struct { RequestedScopes []string `json:"requestedScopes,omitempty"` } +// Credentials for accessing a Git repository type RepoCredentials struct { - URL string `json:"url,omitempty"` - UsernameSecret *apiv1.SecretKeySelector `json:"usernameSecret,omitempty"` - PasswordSecret *apiv1.SecretKeySelector `json:"passwordSecret,omitempty"` - SSHPrivateKeySecret *apiv1.SecretKeySelector `json:"sshPrivateKeySecret,omitempty"` - InsecureIgnoreHostKey bool `json:"insecureIgnoreHostKey,omitempty"` + // The URL to the repository + URL string `json:"url,omitempty"` + // Name of the secret storing the username used to access the repo + UsernameSecret *apiv1.SecretKeySelector `json:"usernameSecret,omitempty"` + // Name of the secret storing the password used to access the repo + PasswordSecret *apiv1.SecretKeySelector `json:"passwordSecret,omitempty"` + // Name of the secret storing the SSH private key used to access the repo + SSHPrivateKeySecret *apiv1.SecretKeySelector `json:"sshPrivateKeySecret,omitempty"` + // Whether to connect the repository in an insecure way (deprecated) + InsecureIgnoreHostKey bool `json:"insecureIgnoreHostKey,omitempty"` + // Whether to connect the repository in an insecure way + Insecure bool `json:"insecure,omitempty"` } type HelmRepoCredentials struct { @@ -196,6 +204,21 @@ func (mgr *SettingsManager) getConfigMap() (*apiv1.ConfigMap, error) { return argoCDCM, err } +// Returns the ConfigMap with the given name from the cluster. +// The ConfigMap must be labeled with "app.kubernetes.io/part-of: argocd" in +// order to be retrievable. +func (mgr *SettingsManager) GetNamedConfigMap(configMapName string) (*apiv1.ConfigMap, error) { + err := mgr.ensureSynced(false) + if err != nil { + return nil, err + } + configMap, err := mgr.configmaps.ConfigMaps(mgr.namespace).Get(configMapName) + if err != nil { + return nil, err + } + return configMap, err +} + func (mgr *SettingsManager) GetResourcesFilter() (*ResourcesFilter, error) { argoCDCM, err := mgr.getConfigMap() if err != nil { @@ -372,8 +395,9 @@ func (mgr *SettingsManager) GetSettings() (*ArgoCDSettings, error) { func (mgr *SettingsManager) initialize(ctx context.Context) error { tweakConfigMap := func(options *metav1.ListOptions) { - cmFieldSelector := fields.ParseSelectorOrDie(fmt.Sprintf("metadata.name=%s", common.ArgoCDConfigMapName)) - options.FieldSelector = cmFieldSelector.String() + //cmFieldSelector := fields.ParseSelectorOrDie(fmt.Sprintf("metadata.name=%s", common.ArgoCDConfigMapName)) + cmLabelSelector := fields.ParseSelectorOrDie("app.kubernetes.io/part-of=argocd") + options.LabelSelector = cmLabelSelector.String() } cmInformer := v1.NewFilteredConfigMapInformer(mgr.clientset, mgr.namespace, 3*time.Minute, cache.Indexers{}, tweakConfigMap) @@ -616,6 +640,51 @@ func (mgr *SettingsManager) SaveSettings(settings *ArgoCDSettings) error { return mgr.ResyncInformers() } +// Save the SSH known host data into the corresponding ConfigMap +func (mgr *SettingsManager) SaveSSHKnownHostsData(ctx context.Context, knownHostsList []string) error { + err := mgr.ensureSynced(false) + if err != nil { + return err + } + + certCM, err := mgr.GetNamedConfigMap(common.ArgoCDKnownHostsConfigMapName) + if err != nil { + return err + } + + if certCM.Data == nil { + certCM.Data = make(map[string]string) + } + + certCM.Data["ssh_known_hosts"] = strings.Join(knownHostsList, "\n") + _, err = mgr.clientset.CoreV1().ConfigMaps(mgr.namespace).Update(certCM) + if err != nil { + return nil + } + + return mgr.ResyncInformers() +} + +func (mgr *SettingsManager) SaveTLSCertificateData(ctx context.Context, tlsCertificates map[string]string) error { + err := mgr.ensureSynced(false) + if err != nil { + return err + } + + certCM, err := mgr.GetNamedConfigMap(common.ArgoCDTLSCertsConfigMapName) + if err != nil { + return err + } + + certCM.Data = tlsCertificates + _, err = mgr.clientset.CoreV1().ConfigMaps(mgr.namespace).Update(certCM) + if err != nil { + return nil + } + + return mgr.ResyncInformers() +} + // NewSettingsManager generates a new SettingsManager pointer and returns it func NewSettingsManager(ctx context.Context, clientset kubernetes.Interface, namespace string) *SettingsManager { diff --git a/util/settings/settings_test.go b/util/settings/settings_test.go index 8b924bcb2cd43..47fd40b51dcd9 100644 --- a/util/settings/settings_test.go +++ b/util/settings/settings_test.go @@ -18,6 +18,9 @@ func TestGetRepositories(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: map[string]string{ "repositories": "\n - url: http://foo\n", @@ -34,6 +37,9 @@ func TestSaveRepositories(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, }) settingsManager := NewSettingsManager(context.Background(), kubeClient, "default") @@ -49,6 +55,9 @@ func TestGetRepositoryCredentials(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: map[string]string{ "repository.credentials": "\n - url: http://foo\n", @@ -65,6 +74,9 @@ func TestGetResourceFilter(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: map[string]string{ "resource.exclusions": "\n - apiGroups: [\"group1\"]\n kinds: [\"kind1\"]\n clusters: [\"cluster1\"]\n", @@ -85,6 +97,9 @@ func TestGetConfigManagementPlugins(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: map[string]string{ "configManagementPlugins": ` @@ -110,6 +125,9 @@ func TestGetAppInstanceLabelKey(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: map[string]string{ "application.instanceLabelKey": "testLabel", @@ -126,6 +144,9 @@ func TestGetResourceOverrides(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: map[string]string{ "resource.customizations": ` @@ -152,6 +173,9 @@ func TestGetHelmRepositories(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: map[string]string{ "helm.repositories": "\n - url: http://foo\n", @@ -169,6 +193,9 @@ func TestGetGoogleAnalytics(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDConfigMapName, Namespace: "default", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, }, Data: map[string]string{ "ga.trackingid": "123",