Repository: argoproj/argo-cd
Pull request #5940 (2021-04-01 04:02:24)

chore: move access checks from api server to repo server
Partially resolves the issue #4420 . Moved access checks from api server to repo server
Note on DCO:

If the DCO action in the integration test fails, one or more of your commits are not signed off. Please click on the *Details* link next to the DCO action for instructions on how to resolve this.

Checklist:

* [ ] Either (a) I've created an [enhancement proposal](https://github.com/argoproj/argo-cd/issues/new/choose) and discussed it with the community, (b) this is a bug fix, or (c) this does not need to be in the release notes.
* [x] The title of the PR states what changed and the related issues number (used for the release note).
* [x] I've included "Closes [ISSUE #]" or "Fixes [ISSUE #]" in the description to automatically close the associated issue.
* [ ] I've updated both the CLI and UI to expose my feature, or I plan to submit a second PR with them.
* [ ] Does this PR require documentation updates?
* [ ] I've updated documentation as required by this PR.
* [x] Optional. My organization is added to USERS.md.
* [x] I have signed off all my commits as required by [DCO](https://github.com/argoproj/argoproj/tree/master/community#contributing-to-argo)
* [x] I have written unit and/or e2e tests for my change. PRs without these are unlikely to be merged.
* [ ] My build is green ([troubleshooting builds](https://argo-cd.readthedocs.io/en/latest/developer-guide/ci/)). 

Signed off by [Ishita Sequeira](@ishitasequeira )

codecov[bot]: # [Codecov](https://codecov.io/gh/argoproj/argo-cd/pull/5940?src=pr&el=h1) Report
> Merging [#5940](https://codecov.io/gh/argoproj/argo-cd/pull/5940?src=pr&el=desc) (e850efc) into [master](https://codecov.io/gh/argoproj/argo-cd/commit/d085636fd72c170d0553a2db1f0de8e6ea0df398?el=desc) (d085636) will **decrease** coverage by `0.07%`.
> The diff coverage is `17.50%`.

> :exclamation: Current head e850efc differs from pull request most recent head 8eef5af. Consider uploading reports for the commit 8eef5af to get more accurate results
[![Impacted file tree graph](https://codecov.io/gh/argoproj/argo-cd/pull/5940/graphs/tree.svg?width=650&height=150&src=pr&token=kf5kwuegwE)](https://codecov.io/gh/argoproj/argo-cd/pull/5940?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master    #5940      +/-   ##
==========================================
- Coverage   40.91%   40.83%   -0.08%     
==========================================
  Files         147      147              
  Lines       19635    19648      +13     
==========================================
- Hits         8033     8024       -9     
- Misses      10497    10522      +25     
+ Partials     1105     1102       -3     
```


| [Impacted Files](https://codecov.io/gh/argoproj/argo-cd/pull/5940?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [reposerver/repository/repository.go](https://codecov.io/gh/argoproj/argo-cd/pull/5940/diff?src=pr&el=tree#diff-cmVwb3NlcnZlci9yZXBvc2l0b3J5L3JlcG9zaXRvcnkuZ28=) | `60.39% <0.00%> (-2.42%)` | :arrow_down: |
| [util/git/client.go](https://codecov.io/gh/argoproj/argo-cd/pull/5940/diff?src=pr&el=tree#diff-dXRpbC9naXQvY2xpZW50Lmdv) | `48.04% <42.85%> (ø)` | |
| [util/argo/argo.go](https://codecov.io/gh/argoproj/argo-cd/pull/5940/diff?src=pr&el=tree#diff-dXRpbC9hcmdvL2FyZ28uZ28=) | `62.00% <100.00%> (+1.24%)` | :arrow_up: |
| [server/application/application.go](https://codecov.io/gh/argoproj/argo-cd/pull/5940/diff?src=pr&el=tree#diff-c2VydmVyL2FwcGxpY2F0aW9uL2FwcGxpY2F0aW9uLmdv) | `30.23% <0.00%> (-0.33%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/argoproj/argo-cd/pull/5940?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/argoproj/argo-cd/pull/5940?src=pr&el=footer). Last update [d085636...8eef5af](https://codecov.io/gh/argoproj/argo-cd/pull/5940?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

ishitasequeira: Thanks @jannfis for the review. I have addressed the PR comments.

Patch:
diff --git a/reposerver/apiclient/mocks/RepoServerServiceClient.go b/reposerver/apiclient/mocks/RepoServerServiceClient.go
index f615a0581..f9585f62b 100644
--- a/reposerver/apiclient/mocks/RepoServerServiceClient.go
+++ b/reposerver/apiclient/mocks/RepoServerServiceClient.go
@@ -169,6 +169,36 @@ func (_m *RepoServerServiceClient) ListApps(ctx context.Context, in *apiclient.L
 	return r0, r1
 }
 
+//
+func (_m *RepoServerServiceClient) TestRepository(ctx context.Context, in *apiclient.TestRepositoryRequest, opts ...grpc.CallOption) (*apiclient.TestRepositoryResponse, error) {
+	_va := make([]interface{}, len(opts))
+	for _i := range opts {
+		_va[_i] = opts[_i]
+	}
+	var _ca []interface{}
+	_ca = append(_ca, ctx, in)
+	_ca = append(_ca, _va...)
+	ret := _m.Called(_ca...)
+
+	var r0 *apiclient.TestRepositoryResponse
+	if rf, ok := ret.Get(0).(func(context.Context, *apiclient.TestRepositoryRequest, ...grpc.CallOption) *apiclient.TestRepositoryResponse); ok {
+		r0 = rf(ctx, in, opts...)
+	} else {
+		if ret.Get(0) != nil {
+			r0 = ret.Get(0).(*apiclient.TestRepositoryResponse)
+		}
+	}
+
+	var r1 error
+	if rf, ok := ret.Get(1).(func(context.Context, *apiclient.TestRepositoryRequest, ...grpc.CallOption) error); ok {
+		r1 = rf(ctx, in, opts...)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
 // ListRefs provides a mock function with given fields: ctx, in, opts
 func (_m *RepoServerServiceClient) ListRefs(ctx context.Context, in *apiclient.ListRefsRequest, opts ...grpc.CallOption) (*apiclient.Refs, error) {
 	_va := make([]interface{}, len(opts))
diff --git a/reposerver/apiclient/repository.pb.go b/reposerver/apiclient/repository.pb.go
index 39d9a9b63..514d13453 100644
--- a/reposerver/apiclient/repository.pb.go
+++ b/reposerver/apiclient/repository.pb.go
@@ -177,6 +177,103 @@ func (m *ManifestRequest) GetVerifySignature() bool {
 	return false
 }
 
+// TestRepositoryRequest is a query to test repository is valid or not and has valid access.
+type TestRepositoryRequest struct {
+	Repo                 *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}             `json:"-"`
+	XXX_unrecognized     []byte               `json:"-"`
+	XXX_sizecache        int32                `json:"-"`
+}
+
+func (m *TestRepositoryRequest) Reset()         { *m = TestRepositoryRequest{} }
+func (m *TestRepositoryRequest) String() string { return proto.CompactTextString(m) }
+func (*TestRepositoryRequest) ProtoMessage()    {}
+func (*TestRepositoryRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_dd8723cfcc820480, []int{1}
+}
+func (m *TestRepositoryRequest) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *TestRepositoryRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_TestRepositoryRequest.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *TestRepositoryRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_TestRepositoryRequest.Merge(m, src)
+}
+func (m *TestRepositoryRequest) XXX_Size() int {
+	return m.Size()
+}
+func (m *TestRepositoryRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_TestRepositoryRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_TestRepositoryRequest proto.InternalMessageInfo
+
+func (m *TestRepositoryRequest) GetRepo() *v1alpha1.Repository {
+	if m != nil {
+		return m.Repo
+	}
+	return nil
+}
+
+// TestRepositoryRequest is a query to test repository is valid or not and has valid access.
+type TestRepositoryResponse struct {
+	// Request to verify the signature when generating the manifests (only for Git repositories)
+	VerifiedRepository   bool     `protobuf:"varint,1,opt,name=verifiedRepository,proto3" json:"verifiedRepository,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *TestRepositoryResponse) Reset()         { *m = TestRepositoryResponse{} }
+func (m *TestRepositoryResponse) String() string { return proto.CompactTextString(m) }
+func (*TestRepositoryResponse) ProtoMessage()    {}
+func (*TestRepositoryResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_dd8723cfcc820480, []int{2}
+}
+func (m *TestRepositoryResponse) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *TestRepositoryResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_TestRepositoryResponse.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *TestRepositoryResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_TestRepositoryResponse.Merge(m, src)
+}
+func (m *TestRepositoryResponse) XXX_Size() int {
+	return m.Size()
+}
+func (m *TestRepositoryResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_TestRepositoryResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_TestRepositoryResponse proto.InternalMessageInfo
+
+func (m *TestRepositoryResponse) GetVerifiedRepository() bool {
+	if m != nil {
+		return m.VerifiedRepository
+	}
+	return false
+}
+
 type ManifestResponse struct {
 	Manifests []string `protobuf:"bytes,1,rep,name=manifests,proto3" json:"manifests,omitempty"`
 	Namespace string   `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"`
@@ -195,7 +292,7 @@ func (m *ManifestResponse) Reset()         { *m = ManifestResponse{} }
 func (m *ManifestResponse) String() string { return proto.CompactTextString(m) }
 func (*ManifestResponse) ProtoMessage()    {}
 func (*ManifestResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{1}
+	return fileDescriptor_dd8723cfcc820480, []int{3}
 }
 func (m *ManifestResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -277,7 +374,7 @@ func (m *ListRefsRequest) Reset()         { *m = ListRefsRequest{} }
 func (m *ListRefsRequest) String() string { return proto.CompactTextString(m) }
 func (*ListRefsRequest) ProtoMessage()    {}
 func (*ListRefsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{2}
+	return fileDescriptor_dd8723cfcc820480, []int{4}
 }
 func (m *ListRefsRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -326,7 +423,7 @@ func (m *Refs) Reset()         { *m = Refs{} }
 func (m *Refs) String() string { return proto.CompactTextString(m) }
 func (*Refs) ProtoMessage()    {}
 func (*Refs) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{3}
+	return fileDescriptor_dd8723cfcc820480, []int{5}
 }
 func (m *Refs) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -382,7 +479,7 @@ func (m *ListAppsRequest) Reset()         { *m = ListAppsRequest{} }
 func (m *ListAppsRequest) String() string { return proto.CompactTextString(m) }
 func (*ListAppsRequest) ProtoMessage()    {}
 func (*ListAppsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{4}
+	return fileDescriptor_dd8723cfcc820480, []int{6}
 }
 func (m *ListAppsRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -437,7 +534,7 @@ func (m *AppList) Reset()         { *m = AppList{} }
 func (m *AppList) String() string { return proto.CompactTextString(m) }
 func (*AppList) ProtoMessage()    {}
 func (*AppList) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{5}
+	return fileDescriptor_dd8723cfcc820480, []int{7}
 }
 func (m *AppList) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -489,7 +586,7 @@ func (m *RepoServerAppDetailsQuery) Reset()         { *m = RepoServerAppDetailsQ
 func (m *RepoServerAppDetailsQuery) String() string { return proto.CompactTextString(m) }
 func (*RepoServerAppDetailsQuery) ProtoMessage()    {}
 func (*RepoServerAppDetailsQuery) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{6}
+	return fileDescriptor_dd8723cfcc820480, []int{8}
 }
 func (m *RepoServerAppDetailsQuery) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -569,7 +666,7 @@ func (m *RepoAppDetailsResponse) Reset()         { *m = RepoAppDetailsResponse{}
 func (m *RepoAppDetailsResponse) String() string { return proto.CompactTextString(m) }
 func (*RepoAppDetailsResponse) ProtoMessage()    {}
 func (*RepoAppDetailsResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{7}
+	return fileDescriptor_dd8723cfcc820480, []int{9}
 }
 func (m *RepoAppDetailsResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -649,7 +746,7 @@ func (m *RepoServerRevisionMetadataRequest) Reset()         { *m = RepoServerRev
 func (m *RepoServerRevisionMetadataRequest) String() string { return proto.CompactTextString(m) }
 func (*RepoServerRevisionMetadataRequest) ProtoMessage()    {}
 func (*RepoServerRevisionMetadataRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{8}
+	return fileDescriptor_dd8723cfcc820480, []int{10}
 }
 func (m *RepoServerRevisionMetadataRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -714,7 +811,7 @@ func (m *KsonnetAppSpec) Reset()         { *m = KsonnetAppSpec{} }
 func (m *KsonnetAppSpec) String() string { return proto.CompactTextString(m) }
 func (*KsonnetAppSpec) ProtoMessage()    {}
 func (*KsonnetAppSpec) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{9}
+	return fileDescriptor_dd8723cfcc820480, []int{11}
 }
 func (m *KsonnetAppSpec) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -783,7 +880,7 @@ func (m *HelmAppSpec) Reset()         { *m = HelmAppSpec{} }
 func (m *HelmAppSpec) String() string { return proto.CompactTextString(m) }
 func (*HelmAppSpec) ProtoMessage()    {}
 func (*HelmAppSpec) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{10}
+	return fileDescriptor_dd8723cfcc820480, []int{12}
 }
 func (m *HelmAppSpec) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -860,7 +957,7 @@ func (m *KustomizeAppSpec) Reset()         { *m = KustomizeAppSpec{} }
 func (m *KustomizeAppSpec) String() string { return proto.CompactTextString(m) }
 func (*KustomizeAppSpec) ProtoMessage()    {}
 func (*KustomizeAppSpec) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{11}
+	return fileDescriptor_dd8723cfcc820480, []int{13}
 }
 func (m *KustomizeAppSpec) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -912,7 +1009,7 @@ func (m *KsonnetEnvironment) Reset()         { *m = KsonnetEnvironment{} }
 func (m *KsonnetEnvironment) String() string { return proto.CompactTextString(m) }
 func (*KsonnetEnvironment) ProtoMessage()    {}
 func (*KsonnetEnvironment) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{12}
+	return fileDescriptor_dd8723cfcc820480, []int{14}
 }
 func (m *KsonnetEnvironment) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -976,7 +1073,7 @@ func (m *KsonnetEnvironmentDestination) Reset()         { *m = KsonnetEnvironmen
 func (m *KsonnetEnvironmentDestination) String() string { return proto.CompactTextString(m) }
 func (*KsonnetEnvironmentDestination) ProtoMessage()    {}
 func (*KsonnetEnvironmentDestination) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{13}
+	return fileDescriptor_dd8723cfcc820480, []int{15}
 }
 func (m *KsonnetEnvironmentDestination) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1030,7 +1127,7 @@ func (m *DirectoryAppSpec) Reset()         { *m = DirectoryAppSpec{} }
 func (m *DirectoryAppSpec) String() string { return proto.CompactTextString(m) }
 func (*DirectoryAppSpec) ProtoMessage()    {}
 func (*DirectoryAppSpec) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{14}
+	return fileDescriptor_dd8723cfcc820480, []int{16}
 }
 func (m *DirectoryAppSpec) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1070,7 +1167,7 @@ func (m *HelmChartsRequest) Reset()         { *m = HelmChartsRequest{} }
 func (m *HelmChartsRequest) String() string { return proto.CompactTextString(m) }
 func (*HelmChartsRequest) ProtoMessage()    {}
 func (*HelmChartsRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{15}
+	return fileDescriptor_dd8723cfcc820480, []int{17}
 }
 func (m *HelmChartsRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1118,7 +1215,7 @@ func (m *HelmChart) Reset()         { *m = HelmChart{} }
 func (m *HelmChart) String() string { return proto.CompactTextString(m) }
 func (*HelmChart) ProtoMessage()    {}
 func (*HelmChart) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{16}
+	return fileDescriptor_dd8723cfcc820480, []int{18}
 }
 func (m *HelmChart) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1172,7 +1269,7 @@ func (m *HelmChartsResponse) Reset()         { *m = HelmChartsResponse{} }
 func (m *HelmChartsResponse) String() string { return proto.CompactTextString(m) }
 func (*HelmChartsResponse) ProtoMessage()    {}
 func (*HelmChartsResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_dd8723cfcc820480, []int{17}
+	return fileDescriptor_dd8723cfcc820480, []int{19}
 }
 func (m *HelmChartsResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1210,6 +1307,8 @@ func (m *HelmChartsResponse) GetItems() []*HelmChart {
 
 func init() {
 	proto.RegisterType((*ManifestRequest)(nil), "repository.ManifestRequest")
+	proto.RegisterType((*TestRepositoryRequest)(nil), "repository.TestRepositoryRequest")
+	proto.RegisterType((*TestRepositoryResponse)(nil), "repository.TestRepositoryResponse")
 	proto.RegisterType((*ManifestResponse)(nil), "repository.ManifestResponse")
 	proto.RegisterType((*ListRefsRequest)(nil), "repository.ListRefsRequest")
 	proto.RegisterType((*Refs)(nil), "repository.Refs")
@@ -1236,89 +1335,92 @@ func init() {
 }
 
 var fileDescriptor_dd8723cfcc820480 = []byte{
-	// 1300 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x4b, 0x6f, 0xdb, 0xc6,
-	0x13, 0x37, 0x25, 0xf9, 0xa1, 0x51, 0x62, 0xcb, 0x9b, 0xfc, 0xf3, 0x67, 0x59, 0x47, 0x70, 0x09,
-	0x34, 0x70, 0x9b, 0x86, 0x42, 0x94, 0xa0, 0x0d, 0x12, 0xa0, 0x80, 0x9a, 0x27, 0xe0, 0x24, 0x76,
-	0xe9, 0xb4, 0x87, 0x22, 0x68, 0xb0, 0xa6, 0xc7, 0xd4, 0x56, 0x14, 0xb9, 0xe1, 0x52, 0x2a, 0x1c,
-	0xa0, 0xe7, 0x1e, 0x7a, 0x6e, 0x3f, 0x44, 0x3f, 0x41, 0x6f, 0x3d, 0xf5, 0x71, 0xec, 0xb1, 0xc7,
-	0x22, 0x9f, 0xa4, 0xd8, 0xe5, 0x6b, 0x45, 0xc9, 0xe9, 0xc1, 0x89, 0x73, 0xb1, 0x77, 0xe7, 0x3d,
-	0xb3, 0xbf, 0x9d, 0x1d, 0x11, 0x2e, 0xc5, 0xc8, 0x23, 0x81, 0xf1, 0x04, 0xe3, 0xae, 0x5a, 0xb2,
-	0x24, 0x8a, 0x8f, 0xb4, 0xa5, 0xc3, 0xe3, 0x28, 0x89, 0x08, 0x94, 0x14, 0xeb, 0xbc, 0x1f, 0xf9,
-	0x91, 0x22, 0x77, 0xe5, 0x2a, 0x95, 0xb0, 0x36, 0xfc, 0x28, 0xf2, 0x03, 0xec, 0x52, 0xce, 0xba,
-	0x34, 0x0c, 0xa3, 0x84, 0x26, 0x2c, 0x0a, 0x45, 0xc6, 0xb5, 0x87, 0x37, 0x84, 0xc3, 0x22, 0xc5,
-	0xf5, 0xa2, 0x18, 0xbb, 0x93, 0xab, 0x5d, 0x1f, 0x43, 0x8c, 0x69, 0x82, 0x07, 0x99, 0xcc, 0x43,
-	0x9f, 0x25, 0x83, 0xf1, 0xbe, 0xe3, 0x45, 0xa3, 0x2e, 0x8d, 0x95, 0x8b, 0x6f, 0xd4, 0xe2, 0x8a,
-	0x77, 0xd0, 0x9d, 0xf4, 0xba, 0x7c, 0xe8, 0x4b, 0x7d, 0xd1, 0xa5, 0x9c, 0x07, 0xcc, 0x53, 0xf6,
-	0xbb, 0x93, 0xab, 0x34, 0xe0, 0x03, 0x3a, 0x63, 0xcd, 0xfe, 0x65, 0x09, 0xd6, 0x1e, 0xd1, 0x90,
-	0x1d, 0xa2, 0x48, 0x5c, 0x7c, 0x3e, 0x46, 0x91, 0x90, 0xa7, 0xd0, 0x90, 0x79, 0x98, 0xc6, 0xa6,
-	0xb1, 0xd5, 0xea, 0x3d, 0x70, 0x4a, 0x87, 0x4e, 0xee, 0x50, 0x2d, 0x9e, 0x79, 0x07, 0xce, 0xa4,
-	0xe7, 0xf0, 0xa1, 0xef, 0x48, 0x87, 0x8e, 0xe6, 0xd0, 0xc9, 0x1d, 0x3a, 0x6e, 0x51, 0x11, 0x57,
-	0x59, 0x25, 0x16, 0xac, 0xc4, 0x38, 0x61, 0x82, 0x45, 0xa1, 0x59, 0xdb, 0x34, 0xb6, 0x9a, 0x6e,
-	0xb1, 0x27, 0x26, 0x2c, 0x87, 0xd1, 0x6d, 0xea, 0x0d, 0xd0, 0xac, 0x6f, 0x1a, 0x5b, 0x2b, 0x6e,
-	0xbe, 0x25, 0x9b, 0xd0, 0xa2, 0x9c, 0x3f, 0xa4, 0xfb, 0x18, 0x6c, 0xe3, 0x91, 0xd9, 0x50, 0x8a,
-	0x3a, 0x49, 0xea, 0x52, 0xce, 0x1f, 0xd3, 0x11, 0x9a, 0x8b, 0x8a, 0x9b, 0x6f, 0xc9, 0x06, 0x34,
-	0x43, 0x3a, 0x42, 0xc1, 0xa9, 0x87, 0xe6, 0x8a, 0xe2, 0x95, 0x04, 0xf2, 0x1d, 0xac, 0x6b, 0x81,
-	0xef, 0x45, 0xe3, 0xd8, 0x43, 0x13, 0x54, 0xea, 0x3b, 0x27, 0x4b, 0xbd, 0x5f, 0x35, 0xeb, 0xce,
-	0x7a, 0x22, 0x5f, 0xc3, 0xa2, 0x02, 0x8d, 0xd9, 0xda, 0xac, 0xbf, 0xd6, 0x6a, 0xa7, 0x66, 0x49,
-	0x08, 0xcb, 0x3c, 0x18, 0xfb, 0x2c, 0x14, 0xe6, 0x19, 0xe5, 0xe1, 0xc9, 0xc9, 0x3c, 0xdc, 0x8e,
-	0xc2, 0x43, 0xe6, 0x3f, 0xa2, 0x21, 0xf5, 0x71, 0x84, 0x61, 0xb2, 0xab, 0x8c, 0xbb, 0xb9, 0x13,
-	0xf2, 0x02, 0xda, 0xc3, 0xb1, 0x48, 0xa2, 0x11, 0x7b, 0x81, 0x3b, 0x5c, 0x81, 0xdb, 0x3c, 0xab,
-	0xaa, 0xf9, 0xf8, 0x64, 0x8e, 0xb7, 0x2b, 0x56, 0xdd, 0x19, 0x3f, 0x12, 0x24, 0xc3, 0xf1, 0x3e,
-	0x7e, 0x89, 0xb1, 0x42, 0xd7, 0x6a, 0x0a, 0x12, 0x8d, 0x94, 0xc2, 0x88, 0x65, 0x3b, 0x61, 0xae,
-	0x6d, 0xd6, 0x53, 0x18, 0x15, 0x24, 0xb2, 0x05, 0x6b, 0x13, 0x8c, 0xd9, 0xe1, 0xd1, 0x1e, 0xf3,
-	0x43, 0x9a, 0x8c, 0x63, 0x34, 0xdb, 0x0a, 0x8a, 0x55, 0xb2, 0xfd, 0xbb, 0x01, 0xed, 0xf2, 0xea,
-	0x08, 0x1e, 0x85, 0x42, 0x61, 0x6d, 0x94, 0xd1, 0x84, 0x69, 0x28, 0xf3, 0x25, 0x61, 0x1a, 0x89,
-	0xb5, 0x2a, 0x12, 0x2f, 0xc0, 0x52, 0xda, 0x63, 0x14, 0xf8, 0x9b, 0x6e, 0xb6, 0x9b, 0xba, 0x31,
-	0x8d, 0xca, 0x8d, 0xe9, 0x00, 0x08, 0x05, 0xa4, 0x27, 0x47, 0x1c, 0xcd, 0x25, 0xc5, 0xd5, 0x28,
-	0xc4, 0x86, 0x33, 0x69, 0xdc, 0x2e, 0x8a, 0x71, 0x90, 0x98, 0xcb, 0x4a, 0x62, 0x8a, 0x66, 0x47,
-	0xb0, 0xf6, 0x90, 0xc9, 0x1c, 0x0e, 0xc5, 0xa9, 0xb4, 0x00, 0xfb, 0x63, 0x68, 0x48, 0x67, 0x32,
-	0xb1, 0xfd, 0x98, 0x86, 0xde, 0x00, 0xf3, 0x5a, 0x15, 0x7b, 0x42, 0xa0, 0x91, 0x50, 0x5f, 0x98,
-	0x35, 0x45, 0x57, 0x6b, 0xfb, 0x07, 0x23, 0x8d, 0xb4, 0xcf, 0xb9, 0x78, 0xeb, 0xcd, 0xca, 0x1e,
-	0xc3, 0x72, 0x9f, 0x73, 0x19, 0x0f, 0xb9, 0x0a, 0x0d, 0xca, 0x79, 0x9a, 0x44, 0xab, 0x77, 0xd1,
-	0xd1, 0x1e, 0x86, 0x4c, 0x44, 0xfe, 0x17, 0x77, 0xc3, 0x44, 0x5a, 0x96, 0xa2, 0xd6, 0x27, 0xd0,
-	0x2c, 0x48, 0xa4, 0x0d, 0xf5, 0x21, 0x1e, 0xa9, 0x1c, 0x9a, 0xae, 0x5c, 0x92, 0xf3, 0xb0, 0x38,
-	0xa1, 0xc1, 0x38, 0x47, 0x49, 0xba, 0xb9, 0x59, 0xbb, 0x61, 0xd8, 0x7f, 0xd7, 0xe1, 0x1d, 0x19,
-	0xe7, 0x9e, 0x02, 0x47, 0x9f, 0xf3, 0x3b, 0x98, 0x50, 0x16, 0x88, 0xcf, 0xc7, 0x18, 0x1f, 0xbd,
-	0xe1, 0x72, 0xf8, 0xb0, 0x94, 0x62, 0x4b, 0x85, 0xf5, 0x06, 0x1a, 0x64, 0x66, 0xbe, 0xec, 0x8a,
-	0xf5, 0x37, 0xd3, 0x15, 0xe7, 0x75, 0xa9, 0xc6, 0x29, 0x75, 0xa9, 0x63, 0x1f, 0x2a, 0xfb, 0xfb,
-	0x1a, 0x5c, 0x90, 0xb1, 0x96, 0x87, 0x5a, 0xf4, 0x15, 0x79, 0x1d, 0xe4, 0x0d, 0x4f, 0x21, 0xa2,
-	0xd6, 0xe4, 0x3a, 0x2c, 0x0f, 0x45, 0x14, 0x86, 0x98, 0x64, 0xc7, 0x61, 0xe9, 0xc0, 0xdb, 0x4e,
-	0x59, 0x7d, 0xce, 0xf7, 0x38, 0x7a, 0x6e, 0x2e, 0x4a, 0x2e, 0x43, 0x63, 0x80, 0xc1, 0x48, 0xf5,
-	0x98, 0x56, 0xef, 0xff, 0xba, 0xca, 0x03, 0x0c, 0x46, 0xb9, 0xbc, 0x12, 0x22, 0x37, 0xa1, 0x59,
-	0xc4, 0x9f, 0x15, 0x68, 0x63, 0xca, 0x49, 0xce, 0xcc, 0xd5, 0x4a, 0x71, 0xa9, 0x7b, 0xc0, 0x62,
-	0xf4, 0xa4, 0xa0, 0xca, 0xb4, 0xa2, 0x7b, 0x27, 0x67, 0x16, 0xba, 0x85, 0xb8, 0xfd, 0x9b, 0x01,
-	0xef, 0x95, 0x20, 0x77, 0xb3, 0x2b, 0xf7, 0x08, 0x13, 0x7a, 0x40, 0x13, 0xfa, 0xf6, 0x07, 0x95,
-	0x4b, 0xb0, 0xea, 0x0d, 0xd0, 0x1b, 0x96, 0x8f, 0x44, 0x3a, 0xaf, 0x54, 0xa8, 0xf6, 0x1f, 0x35,
-	0x58, 0x9d, 0x3e, 0x08, 0x79, 0x92, 0xb2, 0xe5, 0xe7, 0x27, 0x29, 0xd7, 0x64, 0x17, 0xce, 0x60,
-	0x38, 0x61, 0x71, 0x14, 0xca, 0x27, 0x35, 0x47, 0xfd, 0x47, 0xc7, 0x1f, 0xa7, 0x73, 0x57, 0x13,
-	0x4f, 0xdb, 0xca, 0x94, 0x05, 0x12, 0x02, 0x70, 0x1a, 0xd3, 0x11, 0x26, 0x18, 0x4b, 0x68, 0xd7,
-	0x5f, 0x03, 0xb4, 0xd3, 0x08, 0x76, 0x73, 0xb3, 0xae, 0xe6, 0xc1, 0x7a, 0x06, 0xeb, 0x33, 0x21,
-	0xcd, 0x69, 0x6b, 0xd7, 0xf5, 0xb6, 0xd6, 0xea, 0x75, 0xe6, 0x64, 0xa8, 0x99, 0xd1, 0xdb, 0xde,
-	0xaf, 0x35, 0x68, 0x69, 0xf8, 0x9c, 0x5b, 0xc6, 0x0e, 0x80, 0x52, 0xb8, 0xc7, 0x02, 0x4c, 0x8b,
-	0xd8, 0x74, 0x35, 0x0a, 0x19, 0xce, 0x29, 0xca, 0xf6, 0xc9, 0x8a, 0x22, 0x43, 0x9a, 0x5b, 0x11,
-	0xf9, 0x9a, 0x2b, 0xd7, 0x22, 0xbb, 0xe5, 0xd9, 0x8e, 0x7c, 0x0b, 0xab, 0x87, 0x2c, 0xc0, 0xdd,
-	0x32, 0x90, 0x25, 0x15, 0xc8, 0xce, 0xc9, 0x03, 0xb9, 0xa7, 0xdb, 0x75, 0x2b, 0x6e, 0xec, 0x0f,
-	0xa1, 0x5d, 0xbd, 0xae, 0x32, 0x48, 0x36, 0xa2, 0x7e, 0x51, 0xad, 0x6c, 0x67, 0xff, 0x68, 0x00,
-	0x99, 0x3d, 0x8f, 0xe3, 0x8a, 0x3e, 0xbc, 0x21, 0xf2, 0x99, 0x2b, 0xbd, 0x28, 0x1a, 0x85, 0x6c,
-	0x43, 0xeb, 0x00, 0x45, 0xc2, 0x42, 0x15, 0x70, 0xd6, 0x44, 0x3e, 0x78, 0xf5, 0xc1, 0xdf, 0x29,
-	0x15, 0x5c, 0x5d, 0xdb, 0xfe, 0x02, 0x2e, 0xbe, 0x52, 0x5a, 0x9b, 0xa1, 0x8c, 0xa9, 0x19, 0xea,
-	0x95, 0x93, 0x97, 0x4d, 0xa0, 0x5d, 0xed, 0x46, 0xf6, 0x73, 0x58, 0x97, 0x35, 0xbd, 0x3d, 0xa0,
-	0x71, 0x72, 0x4a, 0x73, 0xd1, 0x2d, 0x68, 0x16, 0x2e, 0xe7, 0xd6, 0xda, 0x82, 0x95, 0x49, 0x3e,
-	0xbb, 0xa6, 0x83, 0x51, 0xb1, 0xb7, 0xfb, 0x40, 0xf4, 0x78, 0xb3, 0x77, 0xe3, 0x32, 0x2c, 0xb2,
-	0x04, 0x47, 0xf9, 0x68, 0xf2, 0xbf, 0x6a, 0xbb, 0x57, 0xe2, 0x6e, 0x2a, 0xd3, 0xfb, 0xb9, 0x01,
-	0xeb, 0x65, 0xd7, 0x95, 0x7f, 0x99, 0x87, 0x64, 0x07, 0xda, 0xf7, 0xb3, 0x5f, 0x8d, 0xf9, 0xb8,
-	0x4b, 0xde, 0xd5, 0xed, 0x54, 0x7e, 0x3f, 0x5a, 0x1b, 0xf3, 0x99, 0x69, 0x44, 0xf6, 0x02, 0xb9,
-	0x05, 0x2b, 0xf9, 0xbc, 0x39, 0x6d, 0xa8, 0x32, 0x85, 0x5a, 0x6d, 0x9d, 0x29, 0x19, 0xf6, 0x02,
-	0xf9, 0x34, 0x55, 0x96, 0xb3, 0xd3, 0xac, 0xb2, 0x36, 0x18, 0x5a, 0xe7, 0xe6, 0x4c, 0x61, 0xf6,
-	0x02, 0x79, 0x0a, 0x67, 0xef, 0xab, 0x36, 0x9a, 0xbd, 0xb0, 0xe4, 0xfd, 0x69, 0x27, 0xc7, 0x0c,
-	0x56, 0x96, 0x5d, 0x15, 0x9b, 0x7d, 0xa4, 0xed, 0x05, 0xf2, 0x93, 0x01, 0xe7, 0xee, 0x63, 0x52,
-	0x7d, 0xb0, 0xc8, 0x95, 0xf9, 0x4e, 0x8e, 0x79, 0xd8, 0xac, 0xc7, 0x27, 0x05, 0xd6, 0xb4, 0x59,
-	0x7b, 0x81, 0xec, 0xaa, 0xb4, 0x4b, 0x80, 0x90, 0x8b, 0x73, 0x91, 0x50, 0x54, 0xaf, 0x73, 0x1c,
-	0x3b, 0x4f, 0xf5, 0xb3, 0xfe, 0x9f, 0x2f, 0x3b, 0xc6, 0x5f, 0x2f, 0x3b, 0xc6, 0x3f, 0x2f, 0x3b,
-	0xc6, 0x57, 0xd7, 0xfe, 0xe3, 0xab, 0x84, 0xf6, 0x01, 0x85, 0x72, 0xe6, 0x05, 0x0c, 0xc3, 0x64,
-	0x7f, 0x49, 0x7d, 0x83, 0xb8, 0xf6, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x72, 0xbc, 0x47, 0x0a,
-	0x5f, 0x11, 0x00, 0x00,
+	// 1347 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xcd, 0x6f, 0x1b, 0x45,
+	0x14, 0xcf, 0xda, 0xce, 0x87, 0x9f, 0xdb, 0xc4, 0x99, 0x7e, 0xb0, 0x98, 0xd4, 0x4a, 0x57, 0xa2,
+	0x0a, 0x94, 0xae, 0x55, 0xb7, 0x82, 0xaa, 0x95, 0x90, 0x4c, 0x3f, 0xa5, 0xb4, 0x4d, 0xd8, 0x14,
+	0x24, 0x50, 0x45, 0x35, 0x59, 0xbf, 0xac, 0x07, 0xaf, 0x77, 0xa7, 0xbb, 0x6b, 0xa3, 0x54, 0xe2,
+	0x88, 0x38, 0x70, 0x86, 0xbf, 0x85, 0x1b, 0x27, 0x3e, 0x8e, 0x1c, 0x39, 0xa2, 0xfe, 0x25, 0x68,
+	0x66, 0xbf, 0xc6, 0xeb, 0x4d, 0x38, 0xb8, 0x49, 0x2f, 0xc9, 0xcc, 0xfb, 0x9e, 0x37, 0xbf, 0xf7,
+	0xe6, 0x79, 0xe1, 0x4a, 0x80, 0xdc, 0x0f, 0x31, 0x98, 0x60, 0xd0, 0x91, 0x4b, 0x16, 0xf9, 0xc1,
+	0xa1, 0xb2, 0x34, 0x79, 0xe0, 0x47, 0x3e, 0x81, 0x9c, 0xd2, 0x3a, 0xef, 0xf8, 0x8e, 0x2f, 0xc9,
+	0x1d, 0xb1, 0x8a, 0x25, 0x5a, 0x1b, 0x8e, 0xef, 0x3b, 0x2e, 0x76, 0x28, 0x67, 0x1d, 0xea, 0x79,
+	0x7e, 0x44, 0x23, 0xe6, 0x7b, 0x61, 0xc2, 0x35, 0x86, 0xb7, 0x42, 0x93, 0xf9, 0x92, 0x6b, 0xfb,
+	0x01, 0x76, 0x26, 0xd7, 0x3b, 0x0e, 0x7a, 0x18, 0xd0, 0x08, 0xfb, 0x89, 0xcc, 0x63, 0x87, 0x45,
+	0x83, 0xf1, 0xbe, 0x69, 0xfb, 0xa3, 0x0e, 0x0d, 0xa4, 0x8b, 0x6f, 0xe5, 0xe2, 0x9a, 0xdd, 0xef,
+	0x4c, 0xba, 0x1d, 0x3e, 0x74, 0x84, 0x7e, 0xd8, 0xa1, 0x9c, 0xbb, 0xcc, 0x96, 0xf6, 0x3b, 0x93,
+	0xeb, 0xd4, 0xe5, 0x03, 0x3a, 0x63, 0xcd, 0xf8, 0x75, 0x09, 0xd6, 0x9e, 0x50, 0x8f, 0x1d, 0x60,
+	0x18, 0x59, 0xf8, 0x72, 0x8c, 0x61, 0x44, 0x9e, 0x43, 0x4d, 0x9c, 0x43, 0xd7, 0x36, 0xb5, 0xad,
+	0x46, 0xf7, 0x91, 0x99, 0x3b, 0x34, 0x53, 0x87, 0x72, 0xf1, 0xc2, 0xee, 0x9b, 0x93, 0xae, 0xc9,
+	0x87, 0x8e, 0x29, 0x1c, 0x9a, 0x8a, 0x43, 0x33, 0x75, 0x68, 0x5a, 0x59, 0x46, 0x2c, 0x69, 0x95,
+	0xb4, 0x60, 0x25, 0xc0, 0x09, 0x0b, 0x99, 0xef, 0xe9, 0x95, 0x4d, 0x6d, 0xab, 0x6e, 0x65, 0x7b,
+	0xa2, 0xc3, 0xb2, 0xe7, 0xdf, 0xa5, 0xf6, 0x00, 0xf5, 0xea, 0xa6, 0xb6, 0xb5, 0x62, 0xa5, 0x5b,
+	0xb2, 0x09, 0x0d, 0xca, 0xf9, 0x63, 0xba, 0x8f, 0xee, 0x36, 0x1e, 0xea, 0x35, 0xa9, 0xa8, 0x92,
+	0x84, 0x2e, 0xe5, 0xfc, 0x29, 0x1d, 0xa1, 0xbe, 0x28, 0xb9, 0xe9, 0x96, 0x6c, 0x40, 0xdd, 0xa3,
+	0x23, 0x0c, 0x39, 0xb5, 0x51, 0x5f, 0x91, 0xbc, 0x9c, 0x40, 0xbe, 0x87, 0x75, 0x25, 0xf0, 0x3d,
+	0x7f, 0x1c, 0xd8, 0xa8, 0x83, 0x3c, 0xfa, 0xce, 0x7c, 0x47, 0xef, 0x15, 0xcd, 0x5a, 0xb3, 0x9e,
+	0xc8, 0x37, 0xb0, 0x28, 0x41, 0xa3, 0x37, 0x36, 0xab, 0x6f, 0x34, 0xdb, 0xb1, 0x59, 0xe2, 0xc1,
+	0x32, 0x77, 0xc7, 0x0e, 0xf3, 0x42, 0xfd, 0x8c, 0xf4, 0xf0, 0x6c, 0x3e, 0x0f, 0x77, 0x7d, 0xef,
+	0x80, 0x39, 0x4f, 0xa8, 0x47, 0x1d, 0x1c, 0xa1, 0x17, 0xed, 0x4a, 0xe3, 0x56, 0xea, 0x84, 0xbc,
+	0x82, 0xe6, 0x70, 0x1c, 0x46, 0xfe, 0x88, 0xbd, 0xc2, 0x1d, 0x2e, 0xc1, 0xad, 0x9f, 0x95, 0xd9,
+	0x7c, 0x3a, 0x9f, 0xe3, 0xed, 0x82, 0x55, 0x6b, 0xc6, 0x8f, 0x00, 0xc9, 0x70, 0xbc, 0x8f, 0x5f,
+	0x62, 0x20, 0xd1, 0xb5, 0x1a, 0x83, 0x44, 0x21, 0xc5, 0x30, 0x62, 0xc9, 0x2e, 0xd4, 0xd7, 0x36,
+	0xab, 0x31, 0x8c, 0x32, 0x12, 0xd9, 0x82, 0xb5, 0x09, 0x06, 0xec, 0xe0, 0x70, 0x8f, 0x39, 0x1e,
+	0x8d, 0xc6, 0x01, 0xea, 0x4d, 0x09, 0xc5, 0x22, 0xd9, 0x18, 0xc3, 0x85, 0x67, 0xb2, 0x6a, 0xb2,
+	0x94, 0x9f, 0x46, 0xfd, 0x18, 0x8f, 0xe0, 0x62, 0xd1, 0x6d, 0xc8, 0x7d, 0x2f, 0x44, 0x62, 0x02,
+	0x91, 0x31, 0x32, 0xec, 0xe7, 0x5c, 0x19, 0xc5, 0x8a, 0x55, 0xc2, 0x31, 0xfe, 0xd0, 0xa0, 0x99,
+	0xd7, 0x7e, 0x62, 0x64, 0x03, 0xea, 0xa3, 0x84, 0x16, 0xea, 0x9a, 0xcc, 0x4f, 0x4e, 0x98, 0x2e,
+	0xa5, 0x4a, 0xb1, 0x94, 0x2e, 0xc2, 0x52, 0xdc, 0x24, 0x65, 0xf5, 0xd6, 0xad, 0x64, 0x37, 0x55,
+	0xf2, 0xb5, 0x42, 0xc9, 0xb7, 0x01, 0x42, 0x59, 0x09, 0xcf, 0x0e, 0x39, 0xea, 0x4b, 0x92, 0xab,
+	0x50, 0x88, 0x01, 0x67, 0xe2, 0xc4, 0x5b, 0x18, 0x8e, 0xdd, 0x48, 0x5f, 0x96, 0x12, 0x53, 0x34,
+	0xc3, 0x87, 0xb5, 0xc7, 0x4c, 0x9c, 0xe1, 0x20, 0x3c, 0x9d, 0x3b, 0xf8, 0x18, 0x6a, 0xc2, 0x99,
+	0x38, 0xd8, 0x7e, 0x40, 0x3d, 0x7b, 0x80, 0x69, 0xae, 0xb2, 0x3d, 0x21, 0x50, 0x8b, 0xa8, 0x13,
+	0xea, 0x15, 0x49, 0x97, 0x6b, 0xe3, 0x27, 0x2d, 0x8e, 0xb4, 0xc7, 0x79, 0xf8, 0xd6, 0xbb, 0xad,
+	0x31, 0x86, 0xe5, 0x1e, 0xe7, 0x22, 0x1e, 0x72, 0x1d, 0x6a, 0x94, 0xf3, 0xf8, 0x10, 0x8d, 0xee,
+	0x25, 0x53, 0x79, 0xd9, 0x12, 0x11, 0xf1, 0x3f, 0xbc, 0xef, 0x45, 0xc2, 0xb2, 0x10, 0x6d, 0x7d,
+	0x02, 0xf5, 0x8c, 0x44, 0x9a, 0x50, 0x1d, 0x62, 0x8c, 0xb5, 0xba, 0x25, 0x96, 0xe4, 0x3c, 0x2c,
+	0x4e, 0xa8, 0x3b, 0x4e, 0x51, 0x12, 0x6f, 0x6e, 0x57, 0x6e, 0x69, 0xc6, 0x3f, 0x55, 0x78, 0x57,
+	0xc4, 0xb9, 0x27, 0xc1, 0xd1, 0xe3, 0xfc, 0x1e, 0x46, 0x94, 0xb9, 0xe1, 0xe7, 0x63, 0x0c, 0x0e,
+	0x4f, 0x38, 0x1d, 0x0e, 0x2c, 0xc5, 0xd8, 0x92, 0x61, 0x9d, 0x40, 0x87, 0x4f, 0xcc, 0xe7, 0x6d,
+	0xbd, 0x7a, 0x32, 0x6d, 0xbd, 0xac, 0xcd, 0xd6, 0x4e, 0xa9, 0xcd, 0x1e, 0xf9, 0xd2, 0x1a, 0x3f,
+	0x56, 0xe0, 0xa2, 0x88, 0x35, 0xbf, 0xd4, 0xac, 0xaf, 0x88, 0x72, 0x10, 0x15, 0x1e, 0x43, 0x44,
+	0xae, 0xc9, 0x4d, 0x58, 0x1e, 0x86, 0xbe, 0xe7, 0x61, 0x94, 0x5c, 0x47, 0x4b, 0x05, 0xde, 0x76,
+	0xcc, 0xea, 0x71, 0xbe, 0xc7, 0xd1, 0xb6, 0x52, 0x51, 0x72, 0x15, 0x6a, 0x03, 0x74, 0x47, 0xb2,
+	0xc7, 0x34, 0xba, 0xef, 0xa8, 0x2a, 0x8f, 0xd0, 0x1d, 0xa5, 0xf2, 0x52, 0x88, 0xdc, 0x86, 0x7a,
+	0x16, 0x7f, 0x92, 0xa0, 0x8d, 0x29, 0x27, 0x29, 0x33, 0x55, 0xcb, 0xc5, 0x85, 0x6e, 0x9f, 0x05,
+	0x68, 0xcb, 0x36, 0xba, 0x38, 0xab, 0x7b, 0x2f, 0x65, 0x66, 0xba, 0x99, 0xb8, 0xf1, 0xbb, 0x06,
+	0x97, 0x73, 0x90, 0x5b, 0x49, 0xc9, 0x3d, 0xc1, 0x88, 0xf6, 0x69, 0x44, 0xdf, 0xfe, 0xa4, 0x75,
+	0x05, 0x56, 0xed, 0x01, 0xda, 0xc3, 0xfc, 0x95, 0x8b, 0x07, 0xae, 0x02, 0xd5, 0xf8, 0xb3, 0x02,
+	0xab, 0xd3, 0x17, 0x21, 0x6e, 0x52, 0xb4, 0xfc, 0xf4, 0x26, 0xc5, 0x9a, 0xec, 0xc2, 0x19, 0xf4,
+	0x26, 0x2c, 0xf0, 0x3d, 0x31, 0x13, 0xa4, 0xa8, 0xff, 0xe8, 0xe8, 0xeb, 0x34, 0xef, 0x2b, 0xe2,
+	0x71, 0x5b, 0x99, 0xb2, 0x40, 0x3c, 0x00, 0x4e, 0x03, 0x3a, 0xc2, 0x08, 0x03, 0x01, 0xed, 0xea,
+	0x1b, 0x80, 0x76, 0x1c, 0xc1, 0x6e, 0x6a, 0xd6, 0x52, 0x3c, 0xb4, 0x5e, 0xc0, 0xfa, 0x4c, 0x48,
+	0x25, 0x6d, 0xed, 0xa6, 0xda, 0xd6, 0x1a, 0xdd, 0x76, 0xc9, 0x09, 0x15, 0x33, 0x6a, 0xdb, 0xfb,
+	0xad, 0x02, 0x0d, 0x05, 0x9f, 0xa5, 0x69, 0x6c, 0x03, 0x48, 0x85, 0x07, 0xcc, 0xc5, 0x38, 0x89,
+	0x75, 0x4b, 0xa1, 0x90, 0x61, 0x49, 0x52, 0xb6, 0xe7, 0x4b, 0x8a, 0x08, 0xa9, 0x34, 0x23, 0xe2,
+	0x35, 0x97, 0xae, 0xc3, 0xa4, 0xca, 0x93, 0x1d, 0xf9, 0x0e, 0x56, 0x0f, 0x98, 0x8b, 0xbb, 0x79,
+	0x20, 0x4b, 0x32, 0x90, 0x9d, 0xf9, 0x03, 0x79, 0xa0, 0xda, 0xb5, 0x0a, 0x6e, 0x8c, 0x0f, 0xa1,
+	0x59, 0x2c, 0x57, 0x11, 0x24, 0x1b, 0x51, 0x27, 0xcb, 0x56, 0xb2, 0x33, 0x7e, 0xd6, 0x80, 0xcc,
+	0xde, 0xc7, 0x51, 0x49, 0x1f, 0xde, 0x0a, 0xd3, 0xa1, 0x31, 0x2e, 0x14, 0x85, 0x42, 0xb6, 0xa1,
+	0xd1, 0xc7, 0x30, 0x62, 0x9e, 0x0c, 0x38, 0x69, 0x22, 0x1f, 0x1c, 0x7f, 0xf1, 0xf7, 0x72, 0x05,
+	0x4b, 0xd5, 0x36, 0xbe, 0x80, 0x4b, 0xc7, 0x4a, 0x2b, 0x33, 0x94, 0x36, 0x35, 0x43, 0x1d, 0x3b,
+	0x79, 0x19, 0x04, 0x9a, 0xc5, 0x6e, 0x64, 0xbc, 0x84, 0x75, 0x91, 0xd3, 0xbb, 0x03, 0x1a, 0x44,
+	0xa7, 0x34, 0x17, 0xdd, 0x81, 0x7a, 0xe6, 0xb2, 0x34, 0xd7, 0x2d, 0x58, 0x99, 0xa4, 0xc3, 0x77,
+	0x3c, 0x18, 0x65, 0x7b, 0xa3, 0x07, 0x44, 0x8d, 0x37, 0x79, 0x37, 0xae, 0xc2, 0x22, 0x8b, 0x70,
+	0x94, 0x8e, 0x26, 0x17, 0x8a, 0xed, 0x5e, 0x8a, 0x5b, 0xb1, 0x4c, 0xf7, 0x87, 0x45, 0x58, 0xcf,
+	0xbb, 0xae, 0xf8, 0xcb, 0x6c, 0x24, 0x3b, 0xd0, 0x7c, 0x98, 0xfc, 0xec, 0x4d, 0xc7, 0x5d, 0xf2,
+	0x9e, 0x6a, 0xa7, 0xf0, 0x03, 0xb8, 0xb5, 0x51, 0xce, 0x8c, 0x23, 0x32, 0x16, 0xc8, 0x57, 0xb0,
+	0x3a, 0x3d, 0x82, 0x93, 0xcb, 0xaa, 0x46, 0xe9, 0xaf, 0x82, 0x96, 0x71, 0x9c, 0x48, 0x66, 0xfa,
+	0x0e, 0xac, 0xa4, 0xa3, 0xec, 0x74, 0x8c, 0x85, 0x01, 0xb7, 0xd5, 0x54, 0x99, 0x82, 0x61, 0x2c,
+	0x90, 0x4f, 0x63, 0x65, 0x31, 0x96, 0xcd, 0x2a, 0x2b, 0x33, 0x67, 0xeb, 0x5c, 0xc9, 0x80, 0x67,
+	0x2c, 0x90, 0xe7, 0x70, 0xf6, 0xa1, 0xec, 0xd0, 0xc9, 0xe3, 0x4d, 0xde, 0x9f, 0x76, 0x72, 0xc4,
+	0xcc, 0x36, 0x7d, 0xb4, 0xf2, 0xf7, 0xdf, 0x58, 0x20, 0xbf, 0x68, 0x70, 0xee, 0x21, 0x46, 0xc5,
+	0xb7, 0x90, 0x5c, 0x2b, 0x77, 0x72, 0xc4, 0x9b, 0xd9, 0x7a, 0x3a, 0x2f, 0x66, 0xa7, 0xcd, 0x1a,
+	0x0b, 0x64, 0x57, 0x1e, 0x3b, 0xc7, 0x1e, 0xb9, 0x54, 0x0a, 0xb2, 0x2c, 0x7b, 0xed, 0xa3, 0xd8,
+	0xe9, 0x51, 0x3f, 0xeb, 0xfd, 0xf5, 0xba, 0xad, 0xfd, 0xfd, 0xba, 0xad, 0xfd, 0xfb, 0xba, 0xad,
+	0x7d, 0x7d, 0xe3, 0x7f, 0xbe, 0xd8, 0x28, 0x1f, 0x97, 0x28, 0x67, 0xb6, 0xcb, 0xd0, 0x8b, 0xf6,
+	0x97, 0xe4, 0xf7, 0x99, 0x1b, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0xb9, 0x54, 0xc2, 0xf3, 0x7b,
+	0x12, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -1335,6 +1437,8 @@ const _ = grpc.SupportPackageIsVersion4
 type RepoServerServiceClient interface {
 	// GenerateManifest generates manifest for application in specified repo name and revision
 	GenerateManifest(ctx context.Context, in *ManifestRequest, opts ...grpc.CallOption) (*ManifestResponse, error)
+	// Returns a bool val if the repository is valid and has proper access
+	TestRepository(ctx context.Context, in *TestRepositoryRequest, opts ...grpc.CallOption) (*TestRepositoryResponse, error)
 	// Returns a list of refs (eg. branches and tags) in the repo
 	ListRefs(ctx context.Context, in *ListRefsRequest, opts ...grpc.CallOption) (*Refs, error)
 	// ListApps returns a list of apps in the repo
@@ -1364,6 +1468,15 @@ func (c *repoServerServiceClient) GenerateManifest(ctx context.Context, in *Mani
 	return out, nil
 }
 
+func (c *repoServerServiceClient) TestRepository(ctx context.Context, in *TestRepositoryRequest, opts ...grpc.CallOption) (*TestRepositoryResponse, error) {
+	out := new(TestRepositoryResponse)
+	err := c.cc.Invoke(ctx, "/repository.RepoServerService/TestRepository", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 func (c *repoServerServiceClient) ListRefs(ctx context.Context, in *ListRefsRequest, opts ...grpc.CallOption) (*Refs, error) {
 	out := new(Refs)
 	err := c.cc.Invoke(ctx, "/repository.RepoServerService/ListRefs", in, out, opts...)
@@ -1413,6 +1526,8 @@ func (c *repoServerServiceClient) GetHelmCharts(ctx context.Context, in *HelmCha
 type RepoServerServiceServer interface {
 	// GenerateManifest generates manifest for application in specified repo name and revision
 	GenerateManifest(context.Context, *ManifestRequest) (*ManifestResponse, error)
+	// Returns a bool val if the repository is valid and has proper access
+	TestRepository(context.Context, *TestRepositoryRequest) (*TestRepositoryResponse, error)
 	// Returns a list of refs (eg. branches and tags) in the repo
 	ListRefs(context.Context, *ListRefsRequest) (*Refs, error)
 	// ListApps returns a list of apps in the repo
@@ -1432,6 +1547,9 @@ type UnimplementedRepoServerServiceServer struct {
 func (*UnimplementedRepoServerServiceServer) GenerateManifest(ctx context.Context, req *ManifestRequest) (*ManifestResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method GenerateManifest not implemented")
 }
+func (*UnimplementedRepoServerServiceServer) TestRepository(ctx context.Context, req *TestRepositoryRequest) (*TestRepositoryResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method TestRepository not implemented")
+}
 func (*UnimplementedRepoServerServiceServer) ListRefs(ctx context.Context, req *ListRefsRequest) (*Refs, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method ListRefs not implemented")
 }
@@ -1470,6 +1588,24 @@ func _RepoServerService_GenerateManifest_Handler(srv interface{}, ctx context.Co
 	return interceptor(ctx, in, info, handler)
 }
 
+func _RepoServerService_TestRepository_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(TestRepositoryRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(RepoServerServiceServer).TestRepository(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/repository.RepoServerService/TestRepository",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(RepoServerServiceServer).TestRepository(ctx, req.(*TestRepositoryRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 func _RepoServerService_ListRefs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
 	in := new(ListRefsRequest)
 	if err := dec(in); err != nil {
@@ -1568,6 +1704,10 @@ var _RepoServerService_serviceDesc = grpc.ServiceDesc{
 			MethodName: "GenerateManifest",
 			Handler:    _RepoServerService_GenerateManifest_Handler,
 		},
+		{
+			MethodName: "TestRepository",
+			Handler:    _RepoServerService_TestRepository_Handler,
+		},
 		{
 			MethodName: "ListRefs",
 			Handler:    _RepoServerService_ListRefs_Handler,
@@ -1750,6 +1890,82 @@ func (m *ManifestRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	return len(dAtA) - i, nil
 }
 
+func (m *TestRepositoryRequest) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *TestRepositoryRequest) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *TestRepositoryRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if m.XXX_unrecognized != nil {
+		i -= len(m.XXX_unrecognized)
+		copy(dAtA[i:], m.XXX_unrecognized)
+	}
+	if m.Repo != nil {
+		{
+			size, err := m.Repo.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintRepository(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0xa
+	}
+	return len(dAtA) - i, nil
+}
+
+func (m *TestRepositoryResponse) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *TestRepositoryResponse) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *TestRepositoryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if m.XXX_unrecognized != nil {
+		i -= len(m.XXX_unrecognized)
+		copy(dAtA[i:], m.XXX_unrecognized)
+	}
+	if m.VerifiedRepository {
+		i--
+		if m.VerifiedRepository {
+			dAtA[i] = 1
+		} else {
+			dAtA[i] = 0
+		}
+		i--
+		dAtA[i] = 0x8
+	}
+	return len(dAtA) - i, nil
+}
+
 func (m *ManifestResponse) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -2730,6 +2946,37 @@ func (m *ManifestRequest) Size() (n int) {
 	return n
 }
 
+func (m *TestRepositoryRequest) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if m.Repo != nil {
+		l = m.Repo.Size()
+		n += 1 + l + sovRepository(uint64(l))
+	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
+	return n
+}
+
+func (m *TestRepositoryResponse) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if m.VerifiedRepository {
+		n += 2
+	}
+	if m.XXX_unrecognized != nil {
+		n += len(m.XXX_unrecognized)
+	}
+	return n
+}
+
 func (m *ManifestResponse) Size() (n int) {
 	if m == nil {
 		return 0
@@ -3608,6 +3855,170 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error {
 	}
 	return nil
 }
+func (m *TestRepositoryRequest) 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: TestRepositoryRequest: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: TestRepositoryRequest: 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 msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRepository
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthRepository
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthRepository
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.Repo == nil {
+				m.Repo = &v1alpha1.Repository{}
+			}
+			if err := m.Repo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipRepository(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthRepository
+			}
+			if (iNdEx + 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 *TestRepositoryResponse) 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: TestRepositoryResponse: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: TestRepositoryResponse: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field VerifiedRepository", 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.VerifiedRepository = bool(v != 0)
+		default:
+			iNdEx = preIndex
+			skippy, err := skipRepository(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthRepository
+			}
+			if (iNdEx + 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 *ManifestResponse) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go
index 75d8632b6..11bc40539 100644
--- a/reposerver/repository/repository.go
+++ b/reposerver/repository/repository.go
@@ -1372,3 +1372,35 @@ func (s *Service) GetHelmCharts(ctx context.Context, q *apiclient.HelmChartsRequ
 	}
 	return &res, nil
 }
+
+func (s *Service) TestRepository(ctx context.Context, q *apiclient.TestRepositoryRequest) (*apiclient.TestRepositoryResponse, error) {
+	repo := q.Repo
+	checks := map[string]func() error{
+		"git": func() error {
+			return git.TestRepo(repo.Repo, repo.GetGitCreds(), repo.IsInsecure(), repo.IsLFSEnabled())
+		},
+		"helm": func() error {
+			if repo.EnableOCI {
+				if !helm.IsHelmOciRepo(repo.Repo) {
+					return errors.New("OCI Helm repository URL should include hostname and port only")
+				}
+				_, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI).TestHelmOCI()
+				return err
+			} else {
+				_, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI).GetIndex(false)
+				return err
+			}
+		},
+	}
+	if check, ok := checks[repo.Type]; ok {
+		return &apiclient.TestRepositoryResponse{VerifiedRepository: false}, check()
+	}
+	var err error
+	for _, check := range checks {
+		err = check()
+		if err == nil {
+			return &apiclient.TestRepositoryResponse{VerifiedRepository: true}, nil
+		}
+	}
+	return &apiclient.TestRepositoryResponse{VerifiedRepository: false}, err
+}
diff --git a/reposerver/repository/repository.proto b/reposerver/repository/repository.proto
index 74ead59ad..bbf4823d2 100644
--- a/reposerver/repository/repository.proto
+++ b/reposerver/repository/repository.proto
@@ -28,6 +28,17 @@ message ManifestRequest {
     bool verifySignature = 16;
 }
 
+// TestRepositoryRequest is a query to test repository is valid or not and has valid access.
+message TestRepositoryRequest {
+    github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1;
+}
+
+// TestRepositoryRequest is a query to test repository is valid or not and has valid access.
+message TestRepositoryResponse {
+    // Request to verify the signature when generating the manifests (only for Git repositories)
+    bool verifiedRepository = 1;
+}
+
 message ManifestResponse {
     repeated string manifests = 1;
     string namespace = 2;
@@ -154,6 +165,10 @@ service RepoServerService {
     rpc GenerateManifest(ManifestRequest) returns (ManifestResponse) {
     }
 
+    // Returns a bool val if the repository is valid and has proper access
+    rpc TestRepository(TestRepositoryRequest) returns (TestRepositoryResponse) {
+    }
+    
     // Returns a list of refs (eg. branches and tags) in the repo
     rpc ListRefs(ListRefsRequest) returns (Refs) {
     }
diff --git a/server/repository/repository.go b/server/repository/repository.go
index 36a69c3e5..b58feb194 100644
--- a/server/repository/repository.go
+++ b/server/repository/repository.go
@@ -18,7 +18,6 @@ import (
 	"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
 	servercache "github.com/argoproj/argo-cd/v2/server/cache"
 	"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
-	"github.com/argoproj/argo-cd/v2/util/argo"
 	"github.com/argoproj/argo-cd/v2/util/db"
 	"github.com/argoproj/argo-cd/v2/util/errors"
 	"github.com/argoproj/argo-cd/v2/util/io"
@@ -69,7 +68,7 @@ func (s *Server) getConnectionState(ctx context.Context, url string, forceRefres
 	var err error
 	repo, err := s.db.GetRepository(ctx, url)
 	if err == nil {
-		err = argo.TestRepo(repo)
+		err = s.testRepo(ctx, repo)
 	}
 	if err != nil {
 		connectionState.Status = appsv1.ConnectionStatusFailed
@@ -295,7 +294,8 @@ func (s *Server) CreateRepository(ctx context.Context, q *repositorypkg.RepoCrea
 			}
 			repo.CopyCredentialsFrom(creds)
 		}
-		err = argo.TestRepo(repo)
+
+		err = s.testRepo(ctx, repo)
 		if err != nil {
 			return nil, err
 		}
@@ -405,9 +405,22 @@ func (s *Server) ValidateAccess(ctx context.Context, q *repositorypkg.RepoAccess
 			repo.CopyCredentialsFrom(repoCreds)
 		}
 	}
-	err = argo.TestRepo(repo)
+	err = s.testRepo(ctx, repo)
 	if err != nil {
 		return nil, err
 	}
 	return &repositorypkg.RepoResponse{}, nil
 }
+
+func (s *Server) testRepo(ctx context.Context, repo *appsv1.Repository) error {
+	conn, repoClient, err := s.repoClientset.NewRepoServerClient()
+	if err != nil {
+		return err
+	}
+	defer io.Close(conn)
+
+	_, err = repoClient.TestRepository(ctx, &apiclient.TestRepositoryRequest{
+		Repo: repo,
+	})
+	return err
+}
diff --git a/ui/src/app/applications/components/application-pod-view/pod-view.tsx b/ui/src/app/applications/components/application-pod-view/pod-view.tsx
index 76083df80..af0c73ccf 100644
--- a/ui/src/app/applications/components/application-pod-view/pod-view.tsx
+++ b/ui/src/app/applications/components/application-pod-view/pod-view.tsx
@@ -329,6 +329,19 @@ export class PodView extends React.Component<PodViewProps> {
                 if (groupRefs[p.spec.nodeName]) {
                     const curNode = groupRefs[p.spec.nodeName];
                     curNode.pods.push(p);
+                } else {
+                    if (groupRefs.Unschedulable) {
+                        groupRefs.Unschedulable.pods.push(p);
+                    } else {
+                        groupRefs.Unschedulable = {
+                            type: 'node',
+                            kind: 'node',
+                            name: 'Unschedulable',
+                            pods: [p],
+                            info: [{name: 'Kernel Version', value: 'N/A'}, {name: 'OS/Arch', value: 'N/A'}],
+                            hostResourcesInfo: []
+                        };
+                    }
                 }
             } else if (sortMode === 'parentResource') {
                 rnode.parentRefs.forEach(parentRef => {
diff --git a/util/argo/argo.go b/util/argo/argo.go
index 0e4805d89..f6c1d9a63 100644
--- a/util/argo/argo.go
+++ b/util/argo/argo.go
@@ -3,7 +3,6 @@ package argo
 import (
 	"context"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"strings"
 	"time"
@@ -25,8 +24,6 @@ import (
 	applicationsv1 "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
 	"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
 	"github.com/argoproj/argo-cd/v2/util/db"
-	"github.com/argoproj/argo-cd/v2/util/git"
-	"github.com/argoproj/argo-cd/v2/util/helm"
 	"github.com/argoproj/argo-cd/v2/util/io"
 	"github.com/argoproj/argo-cd/v2/util/settings"
 )
@@ -154,7 +151,7 @@ func WaitForRefresh(ctx context.Context, appIf v1alpha1.ApplicationInterface, na
 	return nil, fmt.Errorf("application refresh deadline exceeded")
 }
 
-func TestRepoWithKnownType(repo *argoappv1.Repository, isHelm bool, isHelmOci bool) error {
+func TestRepoWithKnownType(ctx context.Context, repoClient apiclient.RepoServerServiceClient, repo *argoappv1.Repository, isHelm bool, isHelmOci bool) error {
 	repo = repo.DeepCopy()
 	if isHelm {
 		repo.Type = "helm"
@@ -163,37 +160,10 @@ func TestRepoWithKnownType(repo *argoappv1.Repository, isHelm bool, isHelmOci bo
 	}
 	repo.EnableOCI = repo.EnableOCI || isHelmOci
 
-	return TestRepo(repo)
-}
+	_, err := repoClient.TestRepository(ctx, &apiclient.TestRepositoryRequest{
+		Repo: repo,
+	})
 
-func TestRepo(repo *argoappv1.Repository) error {
-	checks := map[string]func() error{
-		"git": func() error {
-			return git.TestRepo(repo.Repo, repo.GetGitCreds(), repo.IsInsecure(), repo.IsLFSEnabled())
-		},
-		"helm": func() error {
-			if repo.EnableOCI {
-				if !helm.IsHelmOciRepo(repo.Repo) {
-					return errors.New("OCI Helm repository URL should include hostname and port only")
-				}
-				_, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI).TestHelmOCI()
-				return err
-			} else {
-				_, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI).GetIndex(false)
-				return err
-			}
-		},
-	}
-	if check, ok := checks[repo.Type]; ok {
-		return check()
-	}
-	var err error
-	for _, check := range checks {
-		err = check()
-		if err == nil {
-			return nil
-		}
-	}
 	return err
 }
 
@@ -226,7 +196,8 @@ func ValidateRepo(
 	}
 
 	repoAccessible := false
-	err = TestRepoWithKnownType(repo, app.Spec.Source.IsHelm(), app.Spec.Source.IsHelmOci())
+
+	err = TestRepoWithKnownType(ctx, repoClient, repo, app.Spec.Source.IsHelm(), app.Spec.Source.IsHelmOci())
 	if err != nil {
 		conditions = append(conditions, argoappv1.ApplicationCondition{
 			Type:    argoappv1.ApplicationConditionInvalidSpecError,


Test patch:
diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go
index 84dc78096..bf2a366c0 100644
--- a/reposerver/repository/repository_test.go
+++ b/reposerver/repository/repository_test.go
@@ -1467,3 +1467,16 @@ func TestFindManifests_Exclude_NothingMatches(t *testing.T) {
 	assert.ElementsMatch(t,
 		[]string{"nginx-deployment", "nginx-deployment-sub"}, []string{objs[0].GetName(), objs[1].GetName()})
 }
+
+func TestTestRepoOCI(t *testing.T) {
+	service := newService(".")
+	_, err := service.TestRepository(context.Background(), &apiclient.TestRepositoryRequest{
+		Repo: &argoappv1.Repository{
+			Repo:      "https://demo.goharbor.io",
+			Type:      "helm",
+			EnableOCI: true,
+		},
+	})
+	assert.Error(t, err)
+	assert.Equal(t, "OCI Helm repository URL should include hostname and port only", err.Error())
+}
diff --git a/server/application/application_test.go b/server/application/application_test.go
index fd8c79108..10df22c67 100644
--- a/server/application/application_test.go
+++ b/server/application/application_test.go
@@ -100,6 +100,7 @@ func newTestAppServer(objects ...runtime.Object) *Server {
 	mockRepoServiceClient.On("ListApps", mock.Anything, mock.Anything).Return(fakeAppList(), nil)
 	mockRepoServiceClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(&apiclient.ManifestResponse{}, nil)
 	mockRepoServiceClient.On("GetAppDetails", mock.Anything, mock.Anything).Return(&apiclient.RepoAppDetailsResponse{}, nil)
+	mockRepoServiceClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil)
 
 	mockRepoClient := &mocks.Clientset{RepoServerServiceClient: &mockRepoServiceClient}
 
diff --git a/util/argo/argo_test.go b/util/argo/argo_test.go
index a44a91474..2cdd069e0 100644
--- a/util/argo/argo_test.go
+++ b/util/argo/argo_test.go
@@ -245,6 +245,13 @@ func TestValidateRepo(t *testing.T) {
 		KustomizeOptions: kustomizeOptions,
 	}).Return(&apiclient.RepoAppDetailsResponse{}, nil)
 
+	repo.Type = "git"
+	repoClient.On("TestRepository", context.Background(), &apiclient.TestRepositoryRequest{
+		Repo: repo,
+	}).Return(&apiclient.TestRepositoryResponse{
+		VerifiedRepository: true,
+	}, nil)
+
 	repoClientSet := &mocks.Clientset{RepoServerServiceClient: repoClient}
 
 	db := &dbmocks.ArgoDB{}
@@ -743,9 +750,3 @@ func TestFilterByName(t *testing.T) {
 		assert.Len(t, res, 0)
 	})
 }
-
-func TestTestRepoOCI(t *testing.T) {
-	err := TestRepo(&argoappv1.Repository{Repo: "https://demo.goharbor.io", Type: "helm", EnableOCI: true})
-	assert.Error(t, err)
-	assert.Equal(t, "OCI Helm repository URL should include hostname and port only", err.Error())
-}