Repository: operator-framework/operator-lifecycle-manager
Pull request #3115 (2023-11-16 21:08:07)

*: use a stable hash for client-side short-circuits
The previous approach here was to use go-spew, which, unfortunately, is not a stable and germane encoding for objects. We are encoding objects that we send to the Kubernetes API server, so features of go-spew like printing the capacity of slices are not germane. This led to hashes of otherwise identical (as far as the server was concerned) objects to be determined as hashing differently.


openshift-ci[bot]: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/operator-framework/operator-lifecycle-manager/pull/3115#" title="Author self-approved">stevekuznetsov</a>*
**Once this PR has been reviewed and has the lgtm label**, please assign [dinhxuanvu](https://github.com/dinhxuanvu) for approval. For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=operator-framework%2Foperator-lifecycle-manager).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/operator-framework/operator-lifecycle-manager/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["dinhxuanvu"]} -->
openshift-merge-robot: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

Patch:
diff --git a/.github/workflows/sanity.yaml b/.github/workflows/sanity.yaml
index f9f7ab4c2..23f8f0474 100644
--- a/.github/workflows/sanity.yaml
+++ b/.github/workflows/sanity.yaml
@@ -27,3 +27,4 @@ jobs:
       uses: "golangci/golangci-lint-action@v3"
       with:
         version: "v1.51.1"
+  
\ No newline at end of file
diff --git a/go.mod b/go.mod
index fe6a1f60c..5f46fa856 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,6 @@ go 1.20
 require (
 	github.com/blang/semver/v4 v4.0.0
 	github.com/coreos/go-semver v0.3.0
-	github.com/davecgh/go-spew v1.1.1
 	github.com/distribution/distribution v2.7.1+incompatible
 	github.com/evanphx/json-patch v5.6.0+incompatible
 	github.com/fsnotify/fsnotify v1.6.0
@@ -25,8 +24,8 @@ require (
 	github.com/onsi/gomega v1.27.7
 	github.com/openshift/api v3.9.0+incompatible
 	github.com/openshift/client-go v0.0.0-20220525160904-9e1acff93e4a
-	github.com/operator-framework/api v0.18.0
-	github.com/operator-framework/operator-registry v1.30.1
+	github.com/operator-framework/api v0.19.0
+	github.com/operator-framework/operator-registry v1.32.0
 	github.com/otiai10/copy v1.12.0
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus/client_golang v1.15.1
@@ -89,6 +88,7 @@ require (
 	github.com/coreos/go-systemd/v22 v22.5.0 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
 	github.com/cyphar/filepath-securejoin v0.2.4 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/docker/cli v23.0.1+incompatible // indirect
 	github.com/docker/distribution v2.8.2+incompatible // indirect
 	github.com/docker/docker v23.0.3+incompatible // indirect
diff --git a/go.sum b/go.sum
index f6799c311..bcafc0970 100644
--- a/go.sum
+++ b/go.sum
@@ -604,10 +604,10 @@ github.com/openshift/api v0.0.0-20221021112143-4226c2167e40 h1:PxjGCA72RtsdHWToZ
 github.com/openshift/api v0.0.0-20221021112143-4226c2167e40/go.mod h1:aQ6LDasvHMvHZXqLHnX2GRmnfTWCF/iIwz8EMTTIE9A=
 github.com/openshift/client-go v0.0.0-20221019143426-16aed247da5c h1:CV76yFOTXmq9VciBR3Bve5ZWzSxdft7gaMVB3kS0rwg=
 github.com/openshift/client-go v0.0.0-20221019143426-16aed247da5c/go.mod h1:lFMO8mLHXWFzSdYvGNo8ivF9SfF6zInA8ZGw4phRnUE=
-github.com/operator-framework/api v0.18.0 h1:6EdSNeAjin4LRu2YQnQWMJMc6HXS0AQDG+CfaEvFrAo=
-github.com/operator-framework/api v0.18.0/go.mod h1:SCCslqke6AVOJ5JM+NqNE1CHuAgJLScsL66pnPaSMXs=
-github.com/operator-framework/operator-registry v1.30.1 h1:7XvISZrwi+j9z4MIiApRRU+K7v3qMXIcgBs88eQ724Q=
-github.com/operator-framework/operator-registry v1.30.1/go.mod h1:iKVnZsuGjPm6h/jPn4WyQ7JFguRCZMUN+YmsEMu6byA=
+github.com/operator-framework/api v0.19.0 h1:QU1CTJU+CufoeneA5rsNlP/uP96s8vDHWUYDFZTauzA=
+github.com/operator-framework/api v0.19.0/go.mod h1:SCCslqke6AVOJ5JM+NqNE1CHuAgJLScsL66pnPaSMXs=
+github.com/operator-framework/operator-registry v1.32.0 h1:RNazXYt3vBf5FZ+JrNNjq4bNh3tDwlkwZJnC+kmCeKk=
+github.com/operator-framework/operator-registry v1.32.0/go.mod h1:89VshAf6+n0V12vdh43+WOi8i1+XpY+kg6Ao4JO0y6k=
 github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY=
 github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww=
 github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
diff --git a/pkg/controller/install/deployment.go b/pkg/controller/install/deployment.go
index 8d5e72626..ade5fa4ca 100644
--- a/pkg/controller/install/deployment.go
+++ b/pkg/controller/install/deployment.go
@@ -2,7 +2,6 @@ package install
 
 import (
 	"fmt"
-	"hash/fnv"
 	"time"
 
 	log "github.com/sirupsen/logrus"
@@ -10,7 +9,6 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	k8slabels "k8s.io/apimachinery/pkg/labels"
-	"k8s.io/apimachinery/pkg/util/rand"
 	"k8s.io/utils/pointer"
 
 	"github.com/operator-framework/api/pkg/operators/v1alpha1"
@@ -181,7 +179,10 @@ func (i *StrategyDeploymentInstaller) deploymentForSpec(name string, spec appsv1
 	// to 2 ReplicaSets per deployment it manages, saving memory.
 	dep.Spec.RevisionHistoryLimit = pointer.Int32(1)
 
-	hash = HashDeploymentSpec(dep.Spec)
+	hash, err = hashutil.DeepHashObject(&dep.Spec)
+	if err != nil {
+		return nil, "", err
+	}
 	dep.Labels[DeploymentSpecHashLabelKey] = hash
 
 	deployment = dep
@@ -327,11 +328,3 @@ func (i *StrategyDeploymentInstaller) cleanupOrphanedDeployments(deploymentSpecs
 
 	return nil
 }
-
-// HashDeploymentSpec calculates a hash given a copy of the deployment spec from a CSV, stripping any
-// operatorgroup annotations.
-func HashDeploymentSpec(spec appsv1.DeploymentSpec) string {
-	hasher := fnv.New32a()
-	hashutil.DeepHashObject(hasher, &spec)
-	return rand.SafeEncodeString(fmt.Sprint(hasher.Sum32()))
-}
diff --git a/pkg/controller/install/webhook.go b/pkg/controller/install/webhook.go
index a152434ce..d3dee19fb 100644
--- a/pkg/controller/install/webhook.go
+++ b/pkg/controller/install/webhook.go
@@ -3,14 +3,12 @@ package install
 import (
 	"context"
 	"fmt"
-	"hash/fnv"
 
 	log "github.com/sirupsen/logrus"
 	admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/apimachinery/pkg/util/rand"
 	"k8s.io/client-go/util/retry"
 
 	"github.com/operator-framework/api/pkg/operators/v1alpha1"
@@ -285,17 +283,14 @@ func addWebhookLabels(object metav1.Object, webhookDesc v1alpha1.WebhookDescript
 	if labels == nil {
 		labels = map[string]string{}
 	}
+	hash, err := hashutil.DeepHashObject(&webhookDesc)
+	if err != nil {
+		return err
+	}
 	labels[WebhookDescKey] = webhookDesc.GenerateName
-	labels[WebhookHashKey] = HashWebhookDesc(webhookDesc)
+	labels[WebhookHashKey] = hash
 	labels[OLMManagedLabelKey] = OLMManagedLabelValue
 	object.SetLabels(labels)
 
 	return nil
 }
-
-// HashWebhookDesc calculates a hash given a webhookDescription
-func HashWebhookDesc(webhookDesc v1alpha1.WebhookDescription) string {
-	hasher := fnv.New32a()
-	hashutil.DeepHashObject(hasher, &webhookDesc)
-	return rand.SafeEncodeString(fmt.Sprint(hasher.Sum32()))
-}
diff --git a/pkg/controller/operators/olm/apiservices.go b/pkg/controller/operators/olm/apiservices.go
index 69d49e144..3faa32a5e 100644
--- a/pkg/controller/operators/olm/apiservices.go
+++ b/pkg/controller/operators/olm/apiservices.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 
+	hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
 	log "github.com/sirupsen/logrus"
 	appsv1 "k8s.io/api/apps/v1"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -414,7 +415,11 @@ func (a *Operator) areWebhooksAvailable(csv *v1alpha1.ClusterServiceVersion) (bo
 		// Create Webhook Label Selector
 		webhookLabels := ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind)
 		webhookLabels[install.WebhookDescKey] = desc.GenerateName
-		webhookLabels[install.WebhookHashKey] = install.HashWebhookDesc(desc)
+		hash, err := hashutil.DeepHashObject(&desc)
+		if err != nil {
+			return false, err
+		}
+		webhookLabels[install.WebhookHashKey] = hash
 		webhookSelector := labels.SelectorFromSet(webhookLabels).String()
 
 		webhookCount := 0
diff --git a/pkg/controller/operators/olm/operatorgroup.go b/pkg/controller/operators/olm/operatorgroup.go
index a23803a2d..3594c544f 100644
--- a/pkg/controller/operators/olm/operatorgroup.go
+++ b/pkg/controller/operators/olm/operatorgroup.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"crypto/sha256"
 	"fmt"
-	"hash/fnv"
 	"math/big"
 	"reflect"
 	"strings"
@@ -718,7 +717,10 @@ func (a *Operator) ensureCSVsInNamespaces(csv *v1alpha1.ClusterServiceVersion, o
 
 	var copyPrototype v1alpha1.ClusterServiceVersion
 	csvCopyPrototype(csv, &copyPrototype)
-	nonstatus, status := copyableCSVHash(&copyPrototype)
+	nonstatus, status, err := copyableCSVHash(&copyPrototype)
+	if err != nil {
+		return err
+	}
 
 	for _, ns := range namespaces {
 		if ns.GetName() == operatorGroup.Namespace {
@@ -780,7 +782,7 @@ func (a *Operator) ensureCSVsInNamespaces(csv *v1alpha1.ClusterServiceVersion, o
 
 // copyableCSVHash returns a hash of the parts of the given CSV that
 // are relevant to copied CSV projection.
-func copyableCSVHash(original *v1alpha1.ClusterServiceVersion) (string, string) {
+func copyableCSVHash(original *v1alpha1.ClusterServiceVersion) (string, string, error) {
 	shallow := v1alpha1.ClusterServiceVersion{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:        original.Name,
@@ -790,15 +792,16 @@ func copyableCSVHash(original *v1alpha1.ClusterServiceVersion) (string, string)
 		Spec: original.Spec,
 	}
 
-	hash := fnv.New64a()
-	hashutil.DeepHashObject(hash, &shallow)
-	nonstatus := string(hash.Sum(nil))
-
-	hash.Reset()
-	hashutil.DeepHashObject(hash, &original.Status)
-	status := string(hash.Sum(nil))
+	newHash, err := hashutil.DeepHashObject(&shallow)
+	if err != nil {
+		return "", "", err
+	}
+	originalHash, err := hashutil.DeepHashObject(&original.Status)
+	if err != nil {
+		return "", "", err
+	}
 
-	return nonstatus, status
+	return newHash, originalHash, nil
 }
 
 // If returned error is not nil, the returned ClusterServiceVersion
diff --git a/pkg/controller/registry/reconciler/configmap.go b/pkg/controller/registry/reconciler/configmap.go
index 729233f14..2fdb4775b 100644
--- a/pkg/controller/registry/reconciler/configmap.go
+++ b/pkg/controller/registry/reconciler/configmap.go
@@ -6,6 +6,7 @@ import (
 	"fmt"
 
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
+	hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	corev1 "k8s.io/api/core/v1"
@@ -77,7 +78,7 @@ func (s *configMapCatalogSourceDecorator) ConfigMapChanges(configMap *corev1.Con
 	return true
 }
 
-func (s *configMapCatalogSourceDecorator) Service() *corev1.Service {
+func (s *configMapCatalogSourceDecorator) Service() (*corev1.Service, error) {
 	svc := &corev1.Service{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      s.GetName(),
@@ -98,19 +99,25 @@ func (s *configMapCatalogSourceDecorator) Service() *corev1.Service {
 	labels := map[string]string{
 		install.OLMManagedLabelKey: install.OLMManagedLabelValue,
 	}
-	hash := HashServiceSpec(svc.Spec)
+	hash, err := hashutil.DeepHashObject(&svc.Spec)
+	if err != nil {
+		return nil, err
+	}
 	labels[ServiceHashLabelKey] = hash
 	svc.SetLabels(labels)
 	ownerutil.AddOwner(svc, s.CatalogSource, false, false)
-	return svc
+	return svc, nil
 }
 
-func (s *configMapCatalogSourceDecorator) Pod(image string) *corev1.Pod {
-	pod := Pod(s.CatalogSource, "configmap-registry-server", "", "", image, nil, s.Labels(), s.Annotations(), 5, 5, s.runAsUser)
+func (s *configMapCatalogSourceDecorator) Pod(image string) (*corev1.Pod, error) {
+	pod, err := Pod(s.CatalogSource, "configmap-registry-server", "", "", image, nil, s.Labels(), s.Annotations(), 5, 5, s.runAsUser)
+	if err != nil {
+		return nil, err
+	}
 	pod.Spec.ServiceAccountName = s.GetName() + ConfigMapServerPostfix
 	pod.Spec.Containers[0].Command = []string{"configmap-server", "-c", s.Spec.ConfigMap, "-n", s.GetNamespace()}
 	ownerutil.AddOwner(pod, s.CatalogSource, false, true)
-	return pod
+	return pod, nil
 }
 
 func (s *configMapCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccount {
@@ -187,14 +194,18 @@ var _ RegistryEnsurer = &ConfigMapRegistryReconciler{}
 var _ RegistryChecker = &ConfigMapRegistryReconciler{}
 var _ RegistryReconciler = &ConfigMapRegistryReconciler{}
 
-func (c *ConfigMapRegistryReconciler) currentService(source configMapCatalogSourceDecorator) *corev1.Service {
-	serviceName := source.Service().GetName()
+func (c *ConfigMapRegistryReconciler) currentService(source configMapCatalogSourceDecorator) (*corev1.Service, error) {
+	protoService, err := source.Service()
+	if err != nil {
+		return nil, err
+	}
+	serviceName := protoService.GetName()
 	service, err := c.Lister.CoreV1().ServiceLister().Services(source.GetNamespace()).Get(serviceName)
 	if err != nil {
 		logrus.WithField("service", serviceName).Debug("couldn't find service in cache")
-		return nil
+		return nil, nil
 	}
-	return service
+	return service, nil
 }
 
 func (c *ConfigMapRegistryReconciler) currentServiceAccount(source configMapCatalogSourceDecorator) *corev1.ServiceAccount {
@@ -227,30 +238,38 @@ func (c *ConfigMapRegistryReconciler) currentRoleBinding(source configMapCatalog
 	return roleBinding
 }
 
-func (c *ConfigMapRegistryReconciler) currentPods(source configMapCatalogSourceDecorator, image string) []*corev1.Pod {
-	podName := source.Pod(image).GetName()
+func (c *ConfigMapRegistryReconciler) currentPods(source configMapCatalogSourceDecorator, image string) ([]*corev1.Pod, error) {
+	protoPod, err := source.Pod(image)
+	if err != nil {
+		return nil, err
+	}
+	podName := protoPod.GetName()
 	pods, err := c.Lister.CoreV1().PodLister().Pods(source.GetNamespace()).List(labels.SelectorFromSet(source.Selector()))
 	if err != nil {
 		logrus.WithField("pod", podName).WithError(err).Debug("couldn't find pod in cache")
-		return nil
+		return nil, nil
 	}
 	if len(pods) > 1 {
 		logrus.WithField("selector", source.Selector()).Debug("multiple pods found for selector")
 	}
-	return pods
+	return pods, nil
 }
 
-func (c *ConfigMapRegistryReconciler) currentPodsWithCorrectResourceVersion(source configMapCatalogSourceDecorator, image string) []*corev1.Pod {
-	podName := source.Pod(image).GetName()
+func (c *ConfigMapRegistryReconciler) currentPodsWithCorrectResourceVersion(source configMapCatalogSourceDecorator, image string) ([]*corev1.Pod, error) {
+	protoPod, err := source.Pod(image)
+	if err != nil {
+		return nil, err
+	}
+	podName := protoPod.GetName()
 	pods, err := c.Lister.CoreV1().PodLister().Pods(source.GetNamespace()).List(labels.SelectorFromValidatedSet(source.Labels()))
 	if err != nil {
 		logrus.WithField("pod", podName).WithError(err).Debug("couldn't find pod in cache")
-		return nil
+		return nil, nil
 	}
 	if len(pods) > 1 {
 		logrus.WithField("selector", source.Labels()).Debug("multiple pods found for selector")
 	}
-	return pods
+	return pods, nil
 }
 
 // EnsureRegistryServer ensures that all components of registry server are up to date.
@@ -290,7 +309,11 @@ func (c *ConfigMapRegistryReconciler) EnsureRegistryServer(logger *logrus.Entry,
 		}
 
 		// recreate the pod if no existing pod is serving the latest image
-		if len(c.currentPodsWithCorrectResourceVersion(source, image)) == 0 {
+		current, err := c.currentPodsWithCorrectResourceVersion(source, image)
+		if err != nil {
+			return err
+		}
+		if len(current) == 0 {
 			overwritePod = true
 		}
 	}
@@ -305,11 +328,19 @@ func (c *ConfigMapRegistryReconciler) EnsureRegistryServer(logger *logrus.Entry,
 	if err := c.ensureRoleBinding(source, overwrite); err != nil {
 		return errors.Wrapf(err, "error ensuring rolebinding: %s", source.RoleBinding().GetName())
 	}
+	pod, err := source.Pod(image)
+	if err != nil {
+		return err
+	}
 	if err := c.ensurePod(source, overwritePod); err != nil {
-		return errors.Wrapf(err, "error ensuring pod: %s", source.Pod(image).GetName())
+		return errors.Wrapf(err, "error ensuring pod: %s", pod.GetName())
+	}
+	service, err := source.Service()
+	if err != nil {
+		return err
 	}
 	if err := c.ensureService(source, overwrite); err != nil {
-		return errors.Wrapf(err, "error ensuring service: %s", source.Service().GetName())
+		return errors.Wrapf(err, "error ensuring service: %s", service.GetName())
 	}
 
 	if overwritePod {
@@ -317,9 +348,9 @@ func (c *ConfigMapRegistryReconciler) EnsureRegistryServer(logger *logrus.Entry,
 		catalogSource.Status.RegistryServiceStatus = &v1alpha1.RegistryServiceStatus{
 			CreatedAt:        now,
 			Protocol:         "grpc",
-			ServiceName:      source.Service().GetName(),
+			ServiceName:      service.GetName(),
 			ServiceNamespace: source.GetNamespace(),
-			Port:             fmt.Sprintf("%d", source.Service().Spec.Ports[0].Port),
+			Port:             fmt.Sprintf("%d", service.Spec.Ports[0].Port),
 		}
 	}
 	return nil
@@ -368,8 +399,14 @@ func (c *ConfigMapRegistryReconciler) ensureRoleBinding(source configMapCatalogS
 }
 
 func (c *ConfigMapRegistryReconciler) ensurePod(source configMapCatalogSourceDecorator, overwrite bool) error {
-	pod := source.Pod(c.Image)
-	currentPods := c.currentPods(source, c.Image)
+	pod, err := source.Pod(c.Image)
+	if err != nil {
+		return err
+	}
+	currentPods, err := c.currentPods(source, c.Image)
+	if err != nil {
+		return err
+	}
 	if len(currentPods) > 0 {
 		if !overwrite {
 			return nil
@@ -380,7 +417,7 @@ func (c *ConfigMapRegistryReconciler) ensurePod(source configMapCatalogSourceDec
 			}
 		}
 	}
-	_, err := c.OpClient.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).Create(context.TODO(), pod, metav1.CreateOptions{})
+	_, err = c.OpClient.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).Create(context.TODO(), pod, metav1.CreateOptions{})
 	if err == nil {
 		return nil
 	}
@@ -388,8 +425,14 @@ func (c *ConfigMapRegistryReconciler) ensurePod(source configMapCatalogSourceDec
 }
 
 func (c *ConfigMapRegistryReconciler) ensureService(source configMapCatalogSourceDecorator, overwrite bool) error {
-	service := source.Service()
-	svc := c.currentService(source)
+	service, err := source.Service()
+	if err != nil {
+		return err
+	}
+	svc, err := c.currentService(source)
+	if err != nil {
+		return err
+	}
 	if svc != nil {
 		if !overwrite && ServiceHashMatch(svc, service) {
 			return nil
@@ -398,7 +441,7 @@ func (c *ConfigMapRegistryReconciler) ensureService(source configMapCatalogSourc
 			return err
 		}
 	}
-	_, err := c.OpClient.CreateService(service)
+	_, err = c.OpClient.CreateService(service)
 	return err
 }
 
@@ -426,7 +469,11 @@ func (c *ConfigMapRegistryReconciler) CheckRegistryServer(logger *logrus.Entry,
 		}
 
 		// recreate the pod if no existing pod is serving the latest image
-		if len(c.currentPodsWithCorrectResourceVersion(source, image)) == 0 {
+		current, err := c.currentPodsWithCorrectResourceVersion(source, image)
+		if err != nil {
+			return false, err
+		}
+		if len(current) == 0 {
 			return false, nil
 		}
 	}
@@ -434,11 +481,19 @@ func (c *ConfigMapRegistryReconciler) CheckRegistryServer(logger *logrus.Entry,
 	// Check on registry resources
 	// TODO: more complex checks for resources
 	// TODO: add gRPC health check
+	service, err := c.currentService(source)
+	if err != nil {
+		return false, err
+	}
+	pods, err := c.currentPods(source, c.Image)
+	if err != nil {
+		return false, err
+	}
 	if c.currentServiceAccount(source) == nil ||
 		c.currentRole(source) == nil ||
 		c.currentRoleBinding(source) == nil ||
-		c.currentService(source) == nil ||
-		len(c.currentPods(source, c.Image)) < 1 {
+		service == nil ||
+		len(pods) < 1 {
 		healthy = false
 		return
 	}
diff --git a/pkg/controller/registry/reconciler/grpc.go b/pkg/controller/registry/reconciler/grpc.go
index bd9fa11c6..f316a5e79 100644
--- a/pkg/controller/registry/reconciler/grpc.go
+++ b/pkg/controller/registry/reconciler/grpc.go
@@ -3,12 +3,17 @@ package reconciler
 import (
 	"context"
 	"fmt"
-	"hash/fnv"
 	"strings"
 	"time"
 
 	"github.com/google/go-cmp/cmp"
+	"github.com/operator-framework/api/pkg/operators/v1alpha1"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
+	controllerclient "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/controller-runtime/client"
+	hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
+	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
+	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister"
+	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	corev1 "k8s.io/api/core/v1"
@@ -16,14 +21,6 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/util/intstr"
-	"k8s.io/apimachinery/pkg/util/rand"
-
-	"github.com/operator-framework/api/pkg/operators/v1alpha1"
-	controllerclient "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/controller-runtime/client"
-	hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
-	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
-	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorlister"
-	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
 )
 
 const (
@@ -73,7 +70,7 @@ func (s *grpcCatalogSourceDecorator) Annotations() map[string]string {
 	return s.GetAnnotations()
 }
 
-func (s *grpcCatalogSourceDecorator) Service() *corev1.Service {
+func (s *grpcCatalogSourceDecorator) Service() (*corev1.Service, error) {
 	svc := &corev1.Service{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      strings.ReplaceAll(s.GetName(), ".", "-"),
@@ -92,12 +89,15 @@ func (s *grpcCatalogSourceDecorator) Service() *corev1.Service {
 	}
 
 	labels := map[string]string{}
-	hash := HashServiceSpec(svc.Spec)
+	hash, err := hashutil.DeepHashObject(&svc.Spec)
+	if err != nil {
+		return nil, err
+	}
 	labels[ServiceHashLabelKey] = hash
 	labels[install.OLMManagedLabelKey] = install.OLMManagedLabelValue
 	svc.SetLabels(labels)
 	ownerutil.AddOwner(svc, s.CatalogSource, false, false)
-	return svc
+	return svc, nil
 }
 
 func (s *grpcCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccount {
@@ -130,10 +130,13 @@ func (s *grpcCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccount {
 	}
 }
 
-func (s *grpcCatalogSourceDecorator) Pod(serviceAccount *corev1.ServiceAccount) *corev1.Pod {
-	pod := Pod(s.CatalogSource, "registry-server", s.opmImage, s.utilImage, s.Spec.Image, serviceAccount, s.Labels(), s.Annotations(), 5, 10, s.createPodAsUser)
+func (s *grpcCatalogSourceDecorator) Pod(serviceAccount *corev1.ServiceAccount) (*corev1.Pod, error) {
+	pod, err := Pod(s.CatalogSource, "registry-server", s.opmImage, s.utilImage, s.Spec.Image, serviceAccount, s.Labels(), s.Annotations(), 5, 10, s.createPodAsUser)
+	if err != nil {
+		return nil, err
+	}
 	ownerutil.AddOwner(pod, s.CatalogSource, false, true)
-	return pod
+	return pod, nil
 }
 
 type GrpcRegistryReconciler struct {
@@ -148,14 +151,18 @@ type GrpcRegistryReconciler struct {
 
 var _ RegistryReconciler = &GrpcRegistryReconciler{}
 
-func (c *GrpcRegistryReconciler) currentService(source grpcCatalogSourceDecorator) *corev1.Service {
-	serviceName := source.Service().GetName()
+func (c *GrpcRegistryReconciler) currentService(source grpcCatalogSourceDecorator) (*corev1.Service, error) {
+	protoService, err := source.Service()
+	if err != nil {
+		return nil, err
+	}
+	serviceName := protoService.GetName()
 	service, err := c.Lister.CoreV1().ServiceLister().Services(source.GetNamespace()).Get(serviceName)
 	if err != nil {
 		logrus.WithField("service", serviceName).Debug("couldn't find service in cache")
-		return nil
+		return nil, nil
 	}
-	return service
+	return service, nil
 }
 
 func (c *GrpcRegistryReconciler) currentServiceAccount(source grpcCatalogSourceDecorator) *corev1.ServiceAccount {
@@ -192,15 +199,18 @@ func (c *GrpcRegistryReconciler) currentUpdatePods(logger *logrus.Entry, source
 	return pods
 }
 
-func (c *GrpcRegistryReconciler) currentPodsWithCorrectImageAndSpec(logger *logrus.Entry, source grpcCatalogSourceDecorator, serviceAccount *corev1.ServiceAccount) []*corev1.Pod {
+func (c *GrpcRegistryReconciler) currentPodsWithCorrectImageAndSpec(logger *logrus.Entry, source grpcCatalogSourceDecorator, serviceAccount *corev1.ServiceAccount) ([]*corev1.Pod, error) {
 	logger.Info("searching for current pods")
 	pods, err := c.Lister.CoreV1().PodLister().Pods(source.GetNamespace()).List(labels.SelectorFromValidatedSet(source.Labels()))
 	if err != nil {
 		logger.WithError(err).Warn("couldn't find pod in cache")
-		return nil
+		return nil, nil
 	}
 	found := []*corev1.Pod{}
-	newPod := source.Pod(serviceAccount)
+	newPod, err := source.Pod(serviceAccount)
+	if err != nil {
+		return nil, err
+	}
 	for _, p := range pods {
 		images, hash := correctImages(source, p), podHashMatch(p, newPod)
 		logger = logger.WithFields(logrus.Fields{
@@ -216,7 +226,7 @@ func (c *GrpcRegistryReconciler) currentPodsWithCorrectImageAndSpec(logger *logr
 		}
 	}
 	logger.Infof("of %d pods matching label selector, %d have the correct images and matching hash", len(pods), len(found))
-	return found
+	return found, nil
 }
 
 func correctImages(source grpcCatalogSourceDecorator, pod *corev1.Pod) bool {
@@ -239,7 +249,11 @@ func (c *GrpcRegistryReconciler) EnsureRegistryServer(logger *logrus.Entry, cata
 	source := grpcCatalogSourceDecorator{CatalogSource: catalogSource, createPodAsUser: c.createPodAsUser, opmImage: c.opmImage, utilImage: c.utilImage}
 
 	// if service status is nil, we force create every object to ensure they're created the first time
-	overwrite := source.Status.RegistryServiceStatus == nil || !isRegistryServiceStatusValid(&source)
+	valid, err := isRegistryServiceStatusValid(&source)
+	if err != nil {
+		return err
+	}
+	overwrite := !valid
 	if overwrite {
 		logger.Info("registry service status invalid, need to overwrite")
 	}
@@ -256,27 +270,42 @@ func (c *GrpcRegistryReconciler) EnsureRegistryServer(logger *logrus.Entry, cata
 	}
 
 	// recreate the pod if no existing pod is serving the latest image or correct spec
-	overwritePod := overwrite || len(c.currentPodsWithCorrectImageAndSpec(logger, source, sa)) == 0
+	current, err := c.currentPodsWithCorrectImageAndSpec(logger, source, sa)
+	if err != nil {
+		return err
+	}
+	overwritePod := overwrite || len(current) == 0
 	if overwritePod {
 		logger.Info("registry pods invalid, need to overwrite")
 	}
 
+	pod, err := source.Pod(sa)
+	if err != nil {
+		return err
+	}
 	if err := c.ensurePod(logger, source, sa, overwritePod); err != nil {
-		return errors.Wrapf(err, "error ensuring pod: %s", source.Pod(sa).GetName())
+		return errors.Wrapf(err, "error ensuring pod: %s", pod.GetName())
 	}
 	if err := c.ensureUpdatePod(logger, sa, source); err != nil {
 		if _, ok := err.(UpdateNotReadyErr); ok {
 			return err
 		}
-		return errors.Wrapf(err, "error ensuring updated catalog source pod: %s", source.Pod(sa).GetName())
+		return errors.Wrapf(err, "error ensuring updated catalog source pod: %s", pod.GetName())
+	}
+	service, err := source.Service()
+	if err != nil {
+		return err
 	}
 	if err := c.ensureService(source, overwrite); err != nil {
-		return errors.Wrapf(err, "error ensuring service: %s", source.Service().GetName())
+		return errors.Wrapf(err, "error ensuring service: %s", service.GetName())
 	}
 
 	if overwritePod {
 		now := c.now()
-		service := source.Service()
+		service, err := source.Service()
+		if err != nil {
+			return err
+		}
 		catalogSource.Status.RegistryServiceStatus = &v1alpha1.RegistryServiceStatus{
 			CreatedAt:        now,
 			Protocol:         "grpc",
@@ -292,15 +321,19 @@ func getPort(service *corev1.Service) string {
 	return fmt.Sprintf("%d", service.Spec.Ports[0].Port)
 }
 
-func isRegistryServiceStatusValid(source *grpcCatalogSourceDecorator) bool {
-	service := source.Service()
-	if source.Status.RegistryServiceStatus.ServiceName != service.GetName() ||
+func isRegistryServiceStatusValid(source *grpcCatalogSourceDecorator) (bool, error) {
+	service, err := source.Service()
+	if err != nil {
+		return false, err
+	}
+	if source.Status.RegistryServiceStatus == nil ||
+		source.Status.RegistryServiceStatus.ServiceName != service.GetName() ||
 		source.Status.RegistryServiceStatus.ServiceNamespace != service.GetNamespace() ||
 		source.Status.RegistryServiceStatus.Port != getPort(service) ||
 		source.Status.RegistryServiceStatus.Protocol != "grpc" {
-		return false
+		return false, nil
 	}
-	return true
+	return true, nil
 }
 
 func (c *GrpcRegistryReconciler) ensurePod(logger *logrus.Entry, source grpcCatalogSourceDecorator, serviceAccount *corev1.ServiceAccount, overwrite bool) error {
@@ -317,9 +350,12 @@ func (c *GrpcRegistryReconciler) ensurePod(logger *logrus.Entry, source grpcCata
 			}
 		}
 	}
-	desiredPod := source.Pod(serviceAccount)
+	desiredPod, err := source.Pod(serviceAccount)
+	if err != nil {
+		return err
+	}
 	logger.WithFields(logrus.Fields{"pod.namespace": source.GetNamespace(), "pod.name": desiredPod.Namespace}).Info("deleting current pod")
-	_, err := c.OpClient.KubernetesInterface().CoreV1().Pods(source.GetNamespace()).Create(context.TODO(), desiredPod, metav1.CreateOptions{})
+	_, err = c.OpClient.KubernetesInterface().CoreV1().Pods(source.GetNamespace()).Create(context.TODO(), desiredPod, metav1.CreateOptions{})
 	if err != nil {
 		return errors.Wrapf(err, "error creating new pod: %s", desiredPod.GetGenerateName())
 	}
@@ -391,8 +427,14 @@ func (c *GrpcRegistryReconciler) ensureUpdatePod(logger *logrus.Entry, serviceAc
 }
 
 func (c *GrpcRegistryReconciler) ensureService(source grpcCatalogSourceDecorator, overwrite bool) error {
-	service := source.Service()
-	svc := c.currentService(source)
+	service, err := source.Service()
+	if err != nil {
+		return err
+	}
+	svc, err := c.currentService(source)
+	if err != nil {
+		return err
+	}
 	if svc != nil {
 		if !overwrite && ServiceHashMatch(svc, service) {
 			return nil
@@ -402,7 +444,7 @@ func (c *GrpcRegistryReconciler) ensureService(source grpcCatalogSourceDecorator
 			return err
 		}
 	}
-	_, err := c.OpClient.CreateService(service)
+	_, err = c.OpClient.CreateService(service)
 	return err
 }
 
@@ -440,22 +482,18 @@ func ServiceHashMatch(existing, new *corev1.Service) bool {
 	return true
 }
 
-// HashServiceSpec calculates a hash given a copy of the service spec
-func HashServiceSpec(spec corev1.ServiceSpec) string {
-	hasher := fnv.New32a()
-	hashutil.DeepHashObject(hasher, &spec)
-	return rand.SafeEncodeString(fmt.Sprint(hasher.Sum32()))
-}
-
 // createUpdatePod is an internal method that creates a pod using the latest catalog source.
 func (c *GrpcRegistryReconciler) createUpdatePod(source grpcCatalogSourceDecorator, serviceAccount *corev1.ServiceAccount) (*corev1.Pod, error) {
 	// remove label from pod to ensure service does not accidentally route traffic to the pod
-	p := source.Pod(serviceAccount)
+	p, err := source.Pod(serviceAccount)
+	if err != nil {
+		return nil, err
+	}
 	p = swapLabels(p, "", source.Name)
 
 	pod, err := c.OpClient.KubernetesInterface().CoreV1().Pods(source.GetNamespace()).Create(context.TODO(), p, metav1.CreateOptions{})
 	if err != nil {
-		logrus.WithField("pod", source.Pod(serviceAccount).GetName()).Warn("couldn't create new catalogsource pod")
+		logrus.WithField("pod", p.GetName()).Warn("couldn't create new catalogsource pod")
 		return nil, err
 	}
 
@@ -522,8 +560,16 @@ func (c *GrpcRegistryReconciler) CheckRegistryServer(logger *logrus.Entry, catal
 
 	// Check on registry resources
 	// TODO: add gRPC health check
-	if len(c.currentPodsWithCorrectImageAndSpec(logger, source, serviceAccount)) < 1 ||
-		c.currentService(source) == nil || c.currentServiceAccount(source) == nil {
+	service, err := c.currentService(source)
+	if err != nil {
+		return false, err
+	}
+	current, err := c.currentPodsWithCorrectImageAndSpec(logger, source, serviceAccount)
+	if err != nil {
+		return false, err
+	}
+	if len(current) < 1 ||
+		service == nil || c.currentServiceAccount(source) == nil {
 		return false, nil
 	}
 
diff --git a/pkg/controller/registry/reconciler/reconciler.go b/pkg/controller/registry/reconciler/reconciler.go
index efefc07fd..198ca6dc5 100644
--- a/pkg/controller/registry/reconciler/reconciler.go
+++ b/pkg/controller/registry/reconciler/reconciler.go
@@ -3,7 +3,6 @@ package reconciler
 
 import (
 	"fmt"
-	"hash/fnv"
 	"path/filepath"
 
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
@@ -11,7 +10,6 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/util/rand"
 	"k8s.io/utils/pointer"
 
 	operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
@@ -116,7 +114,7 @@ func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient
 	}
 }
 
-func Pod(source *operatorsv1alpha1.CatalogSource, name, opmImg, utilImage, img string, serviceAccount *corev1.ServiceAccount, labels, annotations map[string]string, readinessDelay, livenessDelay int32, runAsUser int64) *corev1.Pod {
+func Pod(source *operatorsv1alpha1.CatalogSource, name, opmImg, utilImage, img string, serviceAccount *corev1.ServiceAccount, labels, annotations map[string]string, readinessDelay, livenessDelay int32, runAsUser int64) (*corev1.Pod, error) {
 	// make a copy of the labels and annotations to avoid mutating the input parameters
 	podLabels := make(map[string]string)
 	podAnnotations := make(map[string]string)
@@ -317,20 +315,17 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name, opmImg, utilImage, img s
 
 	// Add PodSpec hash
 	// This hash info will be used to detect PodSpec changes
-	podLabels[PodHashLabelKey] = hashPodSpec(pod.Spec)
+	hash, err := hashutil.DeepHashObject(&pod.Spec)
+	if err != nil {
+		return nil, err
+	}
+	podLabels[PodHashLabelKey] = hash
 
 	// add eviction annotation to enable the cluster autoscaler to evict the pod in order to drain the node
 	// since catalog pods are not backed by a controller, they cannot be evicted by default
 	podAnnotations[ClusterAutoscalingAnnotationKey] = "true"
 
-	return pod
-}
-
-// hashPodSpec calculates a hash given a copy of the pod spec
-func hashPodSpec(spec corev1.PodSpec) string {
-	hasher := fnv.New32a()
-	hashutil.DeepHashObject(hasher, &spec)
-	return rand.SafeEncodeString(fmt.Sprint(hasher.Sum32()))
+	return pod, nil
 }
 
 func addSecurityContext(pod *corev1.Pod, runAsUser int64) {
diff --git a/pkg/controller/registry/resolver/rbac.go b/pkg/controller/registry/resolver/rbac.go
index f0079e501..4370e1b15 100644
--- a/pkg/controller/registry/resolver/rbac.go
+++ b/pkg/controller/registry/resolver/rbac.go
@@ -4,31 +4,29 @@ import (
 	"crypto/sha256"
 	"encoding/json"
 	"fmt"
-	"hash/fnv"
 	"math/big"
 
-	corev1 "k8s.io/api/core/v1"
-	rbacv1 "k8s.io/api/rbac/v1"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	utilrand "k8s.io/apimachinery/pkg/util/rand"
-
 	"github.com/operator-framework/api/pkg/operators/v1alpha1"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
 	hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
 	"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil"
+	corev1 "k8s.io/api/core/v1"
+	rbacv1 "k8s.io/api/rbac/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
 const maxNameLength = 63
 
-func generateName(base string, o interface{}) string {
-	hasher := fnv.New32a()
-	hashutil.DeepHashObject(hasher, o)
-	hash := utilrand.SafeEncodeString(fmt.Sprint(hasher.Sum32()))
+func generateName(base string, o interface{}) (string, error) {
+	hash, err := hashutil.DeepHashObject(o)
+	if err != nil {
+		return "", err
+	}
 	if len(base)+len(hash) > maxNameLength {
 		base = base[:maxNameLength-len(hash)-1]
 	}
 
-	return fmt.Sprintf("%s-%s", base, hash)
+	return fmt.Sprintf("%s-%s", base, hash), nil
 }
 
 type OperatorPermissions struct {
@@ -125,9 +123,16 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
 		}
 
 		// Create Role
+		name, err := generateName(fmt.Sprintf("%s-%s", csv.GetName(), permission.ServiceAccountName), struct {
+			Name       string                                 `json:"name,omitempty"`
+			Permission v1alpha1.StrategyDeploymentPermissions `json:"permission"`
+		}{Name: csv.GetName(), Permission: permission})
+		if err != nil {
+			return nil, err
+		}
 		role := &rbacv1.Role{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:            generateName(fmt.Sprintf("%s-%s", csv.GetName(), permission.ServiceAccountName), []interface{}{csv.GetName(), permission}),
+				Name:            name,
 				Namespace:       csv.GetNamespace(),
 				OwnerReferences: []metav1.OwnerReference{ownerutil.NonBlockingOwner(csv)},
 				Labels:          ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
@@ -179,9 +184,17 @@ func RBACForClusterServiceVersion(csv *v1alpha1.ClusterServiceVersion) (map[stri
 		}
 
 		// Create ClusterRole
+		name, err := generateName(csv.GetName(), struct {
+			Name       string                                 `json:"name,omitempty"`
+			Namespace  string                                 `json:"namespace,omitempty"`
+			Permission v1alpha1.StrategyDeploymentPermissions `json:"permission"`
+		}{Name: csv.GetName(), Namespace: csv.GetNamespace(), Permission: permission})
+		if err != nil {
+			return nil, err
+		}
 		role := &rbacv1.ClusterRole{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:   generateName(csv.GetName(), []interface{}{csv.GetName(), csv.GetNamespace(), permission}),
+				Name:   name,
 				Labels: ownerutil.OwnerLabel(csv, v1alpha1.ClusterServiceVersionKind),
 			},
 			Rules: permission.Rules,
diff --git a/pkg/lib/kubernetes/pkg/util/hash/hash.go b/pkg/lib/kubernetes/pkg/util/hash/hash.go
index 803f066a4..993f15274 100644
--- a/pkg/lib/kubernetes/pkg/util/hash/hash.go
+++ b/pkg/lib/kubernetes/pkg/util/hash/hash.go
@@ -17,21 +17,39 @@ limitations under the License.
 package hash
 
 import (
-	"hash"
-
-	"github.com/davecgh/go-spew/spew"
+	"crypto/sha256"
+	"encoding/json"
+	"fmt"
+	"math/big"
 )
 
 // DeepHashObject writes specified object to hash using the spew library
 // which follows pointers and prints actual values of the nested objects
 // ensuring the hash does not change when a pointer changes.
-func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) {
+func DeepHashObject(obj interface{}) (string, error) {
+	// While the most accurate encoding we could do for Kubernetes objects (runtime.Object)
+	// would use the API machinery serializers, those operate over entire objects - and
+	// we often need to operate on snippets. Checking with the experts and the implementation,
+	// we can see that the serializers are a thin wrapper over json.Marshal for encoding:
+	// https://github.com/kubernetes/kubernetes/blob/8509ab82b96caa2365552efa08c8ba8baf11c5ec/staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go#L216-L247
+	// Therefore, we can be confident that using json.Marshal() here will:
+	//  1. be stable & idempotent - the library sorts keys, etc.
+	//  2. be germane to our needs - only fields that serialize and are sent to the server
+	//     will be encoded
+
+	hasher := sha256.New224()
 	hasher.Reset()
-	printer := spew.ConfigState{
-		Indent:         " ",
-		SortKeys:       true,
-		DisableMethods: true,
-		SpewKeys:       true,
+	encoder := json.NewEncoder(hasher)
+	if err := encoder.Encode(obj); err != nil {
+		return "", fmt.Errorf("couldn't encode object: %w", err)
 	}
-	printer.Fprintf(hasher, "%#v", objectToWrite)
+
+	// base62(sha224(bytes)) is a useful hash and encoding for adding the contents of this
+	// to a Kubernetes identifier or other field which has length and character set requirements
+	var hash []byte
+	hash = hasher.Sum(hash)
+
+	var i big.Int
+	i.SetBytes(hash[:])
+	return i.Text(62), nil
 }
diff --git a/pkg/package-server/apis/operators/packagemanifest_types.go b/pkg/package-server/apis/operators/packagemanifest_types.go
index e07615576..657a887ad 100644
--- a/pkg/package-server/apis/operators/packagemanifest_types.go
+++ b/pkg/package-server/apis/operators/packagemanifest_types.go
@@ -46,6 +46,9 @@ type PackageManifestStatus struct {
 	// PackageName is the name of the overall package, ala .
 	PackageName string
 
+	// Deprecation is an optional field which contains information if the package is deprecated.
+	Deprecation *Deprecation
+
 	// Channels are the declared channels for the package, ala .
 	// +listType=set
 	Channels []PackageChannel
@@ -81,6 +84,9 @@ type PackageChannel struct {
 	// CurrentCSVSpec holds the spec of the current CSV
 	CurrentCSVDesc CSVDescription
 
+	// Deprecation is an optional field which contains information if the channel is deprecated.
+	Deprecation *Deprecation
+
 	// Entries lists all CSVs in the channel.
 	Entries []ChannelEntry
 }
@@ -92,6 +98,15 @@ type ChannelEntry struct {
 
 	// Version is the version of the bundle for this entry.
 	Version string
+
+	// Deprecation is an optional field which contains information if the channel entry is deprecated.
+	Deprecation *Deprecation
+}
+
+// Deprecation conveys information regarding a deprecated resource.
+type Deprecation struct {
+	// Message is a human readable message describing the deprecation.
+	Message string
 }
 
 // CSVDescription defines a description of a CSV
diff --git a/pkg/package-server/apis/operators/v1/packagemanifest_types.go b/pkg/package-server/apis/operators/v1/packagemanifest_types.go
index c1c24576c..e9cf6a1c1 100644
--- a/pkg/package-server/apis/operators/v1/packagemanifest_types.go
+++ b/pkg/package-server/apis/operators/v1/packagemanifest_types.go
@@ -46,6 +46,9 @@ type PackageManifestStatus struct {
 	// PackageName is the name of the overall package, ala `etcd`.
 	PackageName string `json:"packageName"`
 
+	// Deprecation is an optional field which contains information if the package is deprecated.
+	Deprecation *Deprecation `json:"deprecation,omitempty"`
+
 	// Channels are the declared channels for the package, ala `stable` or `alpha`.
 	// +listType=set
 	Channels []PackageChannel `json:"channels"`
@@ -56,6 +59,12 @@ type PackageManifestStatus struct {
 	DefaultChannel string `json:"defaultChannel"`
 }
 
+// Deprecation conveys information regarding a deprecated resource.
+type Deprecation struct {
+	// Message is a human readable message describing the deprecation.
+	Message string `json:"message"`
+}
+
 // GetDefaultChannel gets the default channel or returns the only one if there's only one. returns empty string if it
 // can't determine the default
 func (m PackageManifest) GetDefaultChannel() string {
@@ -81,6 +90,9 @@ type PackageChannel struct {
 	// CurrentCSVSpec holds the spec of the current CSV
 	CurrentCSVDesc CSVDescription `json:"currentCSVDesc,omitempty"`
 
+	// Deprecation is an optional field which contains information if the channel is deprecated.
+	Deprecation *Deprecation `json:"deprecation,omitempty"`
+
 	// Entries lists all CSVs in the channel, with their upgrade edges.
 	Entries []ChannelEntry `json:"entries"`
 }
@@ -92,6 +104,9 @@ type ChannelEntry struct {
 
 	// Version is the version of the bundle for this entry.
 	Version string `json:"version,omitempty"`
+
+	// Deprecation is an optional field which contains information if the channel entry is deprecated.
+	Deprecation *Deprecation `json:"deprecation,omitempty"`
 }
 
 // CSVDescription defines a description of a CSV
diff --git a/pkg/package-server/apis/operators/v1/zz_generated.conversion.go b/pkg/package-server/apis/operators/v1/zz_generated.conversion.go
index 2bff55779..5ae5b1c98 100644
--- a/pkg/package-server/apis/operators/v1/zz_generated.conversion.go
+++ b/pkg/package-server/apis/operators/v1/zz_generated.conversion.go
@@ -68,6 +68,16 @@ func RegisterConversions(s *runtime.Scheme) error {
 	}); err != nil {
 		return err
 	}
+	if err := s.AddGeneratedConversionFunc((*Deprecation)(nil), (*operators.Deprecation)(nil), func(a, b interface{}, scope conversion.Scope) error {
+		return Convert_v1_Deprecation_To_operators_Deprecation(a.(*Deprecation), b.(*operators.Deprecation), scope)
+	}); err != nil {
+		return err
+	}
+	if err := s.AddGeneratedConversionFunc((*operators.Deprecation)(nil), (*Deprecation)(nil), func(a, b interface{}, scope conversion.Scope) error {
+		return Convert_operators_Deprecation_To_v1_Deprecation(a.(*operators.Deprecation), b.(*Deprecation), scope)
+	}); err != nil {
+		return err
+	}
 	if err := s.AddGeneratedConversionFunc((*Icon)(nil), (*operators.Icon)(nil), func(a, b interface{}, scope conversion.Scope) error {
 		return Convert_v1_Icon_To_operators_Icon(a.(*Icon), b.(*operators.Icon), scope)
 	}); err != nil {
@@ -220,6 +230,7 @@ func Convert_operators_CSVDescription_To_v1_CSVDescription(in *operators.CSVDesc
 func autoConvert_v1_ChannelEntry_To_operators_ChannelEntry(in *ChannelEntry, out *operators.ChannelEntry, s conversion.Scope) error {
 	out.Name = in.Name
 	out.Version = in.Version
+	out.Deprecation = (*operators.Deprecation)(unsafe.Pointer(in.Deprecation))
 	return nil
 }
 
@@ -231,6 +242,7 @@ func Convert_v1_ChannelEntry_To_operators_ChannelEntry(in *ChannelEntry, out *op
 func autoConvert_operators_ChannelEntry_To_v1_ChannelEntry(in *operators.ChannelEntry, out *ChannelEntry, s conversion.Scope) error {
 	out.Name = in.Name
 	out.Version = in.Version
+	out.Deprecation = (*Deprecation)(unsafe.Pointer(in.Deprecation))
 	return nil
 }
 
@@ -239,6 +251,26 @@ func Convert_operators_ChannelEntry_To_v1_ChannelEntry(in *operators.ChannelEntr
 	return autoConvert_operators_ChannelEntry_To_v1_ChannelEntry(in, out, s)
 }
 
+func autoConvert_v1_Deprecation_To_operators_Deprecation(in *Deprecation, out *operators.Deprecation, s conversion.Scope) error {
+	out.Message = in.Message
+	return nil
+}
+
+// Convert_v1_Deprecation_To_operators_Deprecation is an autogenerated conversion function.
+func Convert_v1_Deprecation_To_operators_Deprecation(in *Deprecation, out *operators.Deprecation, s conversion.Scope) error {
+	return autoConvert_v1_Deprecation_To_operators_Deprecation(in, out, s)
+}
+
+func autoConvert_operators_Deprecation_To_v1_Deprecation(in *operators.Deprecation, out *Deprecation, s conversion.Scope) error {
+	out.Message = in.Message
+	return nil
+}
+
+// Convert_operators_Deprecation_To_v1_Deprecation is an autogenerated conversion function.
+func Convert_operators_Deprecation_To_v1_Deprecation(in *operators.Deprecation, out *Deprecation, s conversion.Scope) error {
+	return autoConvert_operators_Deprecation_To_v1_Deprecation(in, out, s)
+}
+
 func autoConvert_v1_Icon_To_operators_Icon(in *Icon, out *operators.Icon, s conversion.Scope) error {
 	out.Base64Data = in.Base64Data
 	out.Mediatype = in.Mediatype
@@ -289,6 +321,7 @@ func autoConvert_v1_PackageChannel_To_operators_PackageChannel(in *PackageChanne
 	if err := Convert_v1_CSVDescription_To_operators_CSVDescription(&in.CurrentCSVDesc, &out.CurrentCSVDesc, s); err != nil {
 		return err
 	}
+	out.Deprecation = (*operators.Deprecation)(unsafe.Pointer(in.Deprecation))
 	out.Entries = *(*[]operators.ChannelEntry)(unsafe.Pointer(&in.Entries))
 	return nil
 }
@@ -304,6 +337,7 @@ func autoConvert_operators_PackageChannel_To_v1_PackageChannel(in *operators.Pac
 	if err := Convert_operators_CSVDescription_To_v1_CSVDescription(&in.CurrentCSVDesc, &out.CurrentCSVDesc, s); err != nil {
 		return err
 	}
+	out.Deprecation = (*Deprecation)(unsafe.Pointer(in.Deprecation))
 	out.Entries = *(*[]ChannelEntry)(unsafe.Pointer(&in.Entries))
 	return nil
 }
@@ -394,6 +428,7 @@ func autoConvert_v1_PackageManifestStatus_To_operators_PackageManifestStatus(in
 		return err
 	}
 	out.PackageName = in.PackageName
+	out.Deprecation = (*operators.Deprecation)(unsafe.Pointer(in.Deprecation))
 	out.Channels = *(*[]operators.PackageChannel)(unsafe.Pointer(&in.Channels))
 	out.DefaultChannel = in.DefaultChannel
 	return nil
@@ -413,6 +448,7 @@ func autoConvert_operators_PackageManifestStatus_To_v1_PackageManifestStatus(in
 		return err
 	}
 	out.PackageName = in.PackageName
+	out.Deprecation = (*Deprecation)(unsafe.Pointer(in.Deprecation))
 	out.Channels = *(*[]PackageChannel)(unsafe.Pointer(&in.Channels))
 	out.DefaultChannel = in.DefaultChannel
 	return nil
diff --git a/pkg/package-server/apis/operators/v1/zz_generated.deepcopy.go b/pkg/package-server/apis/operators/v1/zz_generated.deepcopy.go
index 7147c0955..45a63e69a 100644
--- a/pkg/package-server/apis/operators/v1/zz_generated.deepcopy.go
+++ b/pkg/package-server/apis/operators/v1/zz_generated.deepcopy.go
@@ -108,6 +108,11 @@ func (in *CSVDescription) DeepCopy() *CSVDescription {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ChannelEntry) DeepCopyInto(out *ChannelEntry) {
 	*out = *in
+	if in.Deprecation != nil {
+		in, out := &in.Deprecation, &out.Deprecation
+		*out = new(Deprecation)
+		**out = **in
+	}
 	return
 }
 
@@ -121,6 +126,22 @@ func (in *ChannelEntry) DeepCopy() *ChannelEntry {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Deprecation) DeepCopyInto(out *Deprecation) {
+	*out = *in
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Deprecation.
+func (in *Deprecation) DeepCopy() *Deprecation {
+	if in == nil {
+		return nil
+	}
+	out := new(Deprecation)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Icon) DeepCopyInto(out *Icon) {
 	*out = *in
@@ -157,10 +178,17 @@ func (in *Maintainer) DeepCopy() *Maintainer {
 func (in *PackageChannel) DeepCopyInto(out *PackageChannel) {
 	*out = *in
 	in.CurrentCSVDesc.DeepCopyInto(&out.CurrentCSVDesc)
+	if in.Deprecation != nil {
+		in, out := &in.Deprecation, &out.Deprecation
+		*out = new(Deprecation)
+		**out = **in
+	}
 	if in.Entries != nil {
 		in, out := &in.Entries, &out.Entries
 		*out = make([]ChannelEntry, len(*in))
-		copy(*out, *in)
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
 	}
 	return
 }
@@ -256,6 +284,11 @@ func (in *PackageManifestSpec) DeepCopy() *PackageManifestSpec {
 func (in *PackageManifestStatus) DeepCopyInto(out *PackageManifestStatus) {
 	*out = *in
 	out.Provider = in.Provider
+	if in.Deprecation != nil {
+		in, out := &in.Deprecation, &out.Deprecation
+		*out = new(Deprecation)
+		**out = **in
+	}
 	if in.Channels != nil {
 		in, out := &in.Channels, &out.Channels
 		*out = make([]PackageChannel, len(*in))
diff --git a/pkg/package-server/apis/operators/zz_generated.deepcopy.go b/pkg/package-server/apis/operators/zz_generated.deepcopy.go
index e3b4d8f1b..33a333b2d 100644
--- a/pkg/package-server/apis/operators/zz_generated.deepcopy.go
+++ b/pkg/package-server/apis/operators/zz_generated.deepcopy.go
@@ -108,6 +108,11 @@ func (in *CSVDescription) DeepCopy() *CSVDescription {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *ChannelEntry) DeepCopyInto(out *ChannelEntry) {
 	*out = *in
+	if in.Deprecation != nil {
+		in, out := &in.Deprecation, &out.Deprecation
+		*out = new(Deprecation)
+		**out = **in
+	}
 	return
 }
 
@@ -121,6 +126,22 @@ func (in *ChannelEntry) DeepCopy() *ChannelEntry {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Deprecation) DeepCopyInto(out *Deprecation) {
+	*out = *in
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Deprecation.
+func (in *Deprecation) DeepCopy() *Deprecation {
+	if in == nil {
+		return nil
+	}
+	out := new(Deprecation)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Icon) DeepCopyInto(out *Icon) {
 	*out = *in
@@ -157,10 +178,17 @@ func (in *Maintainer) DeepCopy() *Maintainer {
 func (in *PackageChannel) DeepCopyInto(out *PackageChannel) {
 	*out = *in
 	in.CurrentCSVDesc.DeepCopyInto(&out.CurrentCSVDesc)
+	if in.Deprecation != nil {
+		in, out := &in.Deprecation, &out.Deprecation
+		*out = new(Deprecation)
+		**out = **in
+	}
 	if in.Entries != nil {
 		in, out := &in.Entries, &out.Entries
 		*out = make([]ChannelEntry, len(*in))
-		copy(*out, *in)
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
 	}
 	return
 }
@@ -256,6 +284,11 @@ func (in *PackageManifestSpec) DeepCopy() *PackageManifestSpec {
 func (in *PackageManifestStatus) DeepCopyInto(out *PackageManifestStatus) {
 	*out = *in
 	out.Provider = in.Provider
+	if in.Deprecation != nil {
+		in, out := &in.Deprecation, &out.Deprecation
+		*out = new(Deprecation)
+		**out = **in
+	}
 	if in.Channels != nil {
 		in, out := &in.Channels, &out.Channels
 		*out = make([]PackageChannel, len(*in))
diff --git a/pkg/package-server/client/openapi/zz_generated.openapi.go b/pkg/package-server/client/openapi/zz_generated.openapi.go
index db9a49628..3c805cfba 100644
--- a/pkg/package-server/client/openapi/zz_generated.openapi.go
+++ b/pkg/package-server/client/openapi/zz_generated.openapi.go
@@ -63,6 +63,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
 		"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.AppLink":               schema_package_server_apis_operators_v1_AppLink(ref),
 		"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.CSVDescription":        schema_package_server_apis_operators_v1_CSVDescription(ref),
 		"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.ChannelEntry":          schema_package_server_apis_operators_v1_ChannelEntry(ref),
+		"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.Deprecation":           schema_package_server_apis_operators_v1_Deprecation(ref),
 		"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.Icon":                  schema_package_server_apis_operators_v1_Icon(ref),
 		"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.Maintainer":            schema_package_server_apis_operators_v1_Maintainer(ref),
 		"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.PackageChannel":        schema_package_server_apis_operators_v1_PackageChannel(ref),
@@ -1960,10 +1961,40 @@ func schema_package_server_apis_operators_v1_ChannelEntry(ref common.ReferenceCa
 							Format:      "",
 						},
 					},
+					"deprecation": {
+						SchemaProps: spec.SchemaProps{
+							Description: "Deprecation is an optional field which contains information if the channel entry is deprecated.",
+							Ref:         ref("github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.Deprecation"),
+						},
+					},
 				},
 				Required: []string{"name"},
 			},
 		},
+		Dependencies: []string{
+			"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.Deprecation"},
+	}
+}
+
+func schema_package_server_apis_operators_v1_Deprecation(ref common.ReferenceCallback) common.OpenAPIDefinition {
+	return common.OpenAPIDefinition{
+		Schema: spec.Schema{
+			SchemaProps: spec.SchemaProps{
+				Description: "Deprecation conveys information regarding a deprecated resource.",
+				Type:        []string{"object"},
+				Properties: map[string]spec.Schema{
+					"message": {
+						SchemaProps: spec.SchemaProps{
+							Description: "Message is a human readable message describing the deprecation.",
+							Default:     "",
+							Type:        []string{"string"},
+							Format:      "",
+						},
+					},
+				},
+				Required: []string{"message"},
+			},
+		},
 	}
 }
 
@@ -2047,6 +2078,12 @@ func schema_package_server_apis_operators_v1_PackageChannel(ref common.Reference
 							Ref:         ref("github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.CSVDescription"),
 						},
 					},
+					"deprecation": {
+						SchemaProps: spec.SchemaProps{
+							Description: "Deprecation is an optional field which contains information if the channel is deprecated.",
+							Ref:         ref("github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.Deprecation"),
+						},
+					},
 					"entries": {
 						SchemaProps: spec.SchemaProps{
 							Description: "Entries lists all CSVs in the channel, with their upgrade edges.",
@@ -2066,7 +2103,7 @@ func schema_package_server_apis_operators_v1_PackageChannel(ref common.Reference
 			},
 		},
 		Dependencies: []string{
-			"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.CSVDescription", "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.ChannelEntry"},
+			"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.CSVDescription", "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.ChannelEntry", "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.Deprecation"},
 	}
 }
 
@@ -2234,6 +2271,12 @@ func schema_package_server_apis_operators_v1_PackageManifestStatus(ref common.Re
 							Format:      "",
 						},
 					},
+					"deprecation": {
+						SchemaProps: spec.SchemaProps{
+							Description: "Deprecation is an optional field which contains information if the package is deprecated.",
+							Ref:         ref("github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.Deprecation"),
+						},
+					},
 					"channels": {
 						VendorExtensible: spec.VendorExtensible{
 							Extensions: spec.Extensions{
@@ -2266,7 +2309,7 @@ func schema_package_server_apis_operators_v1_PackageManifestStatus(ref common.Re
 			},
 		},
 		Dependencies: []string{
-			"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.AppLink", "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.PackageChannel"},
+			"github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.AppLink", "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.Deprecation", "github.com/operator-framework/operator-lifecycle-manager/pkg/package-server/apis/operators/v1.PackageChannel"},
 	}
 }
 
diff --git a/pkg/package-server/provider/registry.go b/pkg/package-server/provider/registry.go
index 37deaf84d..2163db943 100644
--- a/pkg/package-server/provider/registry.go
+++ b/pkg/package-server/provider/registry.go
@@ -268,6 +268,15 @@ func (p *RegistryProvider) registryClient(key registry.CatalogKey) (client *regi
 	return
 }
 
+func getOperatorDeprecation(in *api.Deprecation) *operators.Deprecation {
+	if in == nil {
+		return nil
+	}
+	return &operators.Deprecation{
+		Message: in.Message,
+	}
+}
+
 func (p *RegistryProvider) refreshCache(ctx context.Context, client *registryClient) error {
 	key, err := client.key()
 	if err != nil {
@@ -302,9 +311,11 @@ func (p *RegistryProvider) refreshCache(ctx context.Context, client *registryCli
 		if _, ok := bundles[bundle.PackageName]; !ok {
 			bundles[bundle.PackageName] = map[string][]operators.ChannelEntry{}
 		}
+
 		bundles[bundle.PackageName][bundle.ChannelName] = append(bundles[bundle.PackageName][bundle.ChannelName], operators.ChannelEntry{
-			Name:    bundle.CsvName,
-			Version: bundle.Version,
+			Name:        bundle.CsvName,
+			Version:     bundle.Version,
+			Deprecation: getOperatorDeprecation(bundle.Deprecation),
 		})
 	}
 
@@ -532,6 +543,7 @@ func newPackageManifest(ctx context.Context, logger *logrus.Entry, pkg *api.Pack
 			CatalogSourceNamespace:   catsrc.GetNamespace(),
 			PackageName:              pkg.Name,
 			DefaultChannel:           pkg.GetDefaultChannelName(),
+			Deprecation:              getOperatorDeprecation(pkg.Deprecation),
 		},
 	}
 
@@ -565,6 +577,7 @@ func newPackageManifest(ctx context.Context, logger *logrus.Entry, pkg *api.Pack
 			CurrentCSV:     csv.GetName(),
 			CurrentCSVDesc: operators.CreateCSVDescription(&csv, bundle.GetCsvJson()),
 			Entries:        entriesByChannel[pkgChannel.GetName()],
+			Deprecation:    getOperatorDeprecation(pkgChannel.Deprecation),
 		})
 
 		if manifest.Status.DefaultChannel != "" && pkgChannel.GetName() == manifest.Status.DefaultChannel || !providerSet {
diff --git a/vendor/github.com/operator-framework/api/pkg/validation/errors/error.go b/vendor/github.com/operator-framework/api/pkg/validation/errors/error.go
index 9b4391658..4e22d6286 100644
--- a/vendor/github.com/operator-framework/api/pkg/validation/errors/error.go
+++ b/vendor/github.com/operator-framework/api/pkg/validation/errors/error.go
@@ -102,6 +102,7 @@ const (
 	ErrorInvalidPackageManifest   ErrorType = "PackageManifestNotValid"
 	ErrorObjectFailedValidation   ErrorType = "ObjectFailedValidation"
 	ErrorPropertiesAnnotationUsed ErrorType = "PropertiesAnnotationUsed"
+	ErrorDeprecatedValidator      ErrorType = "DeprecatedValidator"
 )
 
 func NewError(t ErrorType, detail, field string, v interface{}) Error {
@@ -248,3 +249,7 @@ func WarnInvalidObject(detail string, value interface{}) Error {
 func WarnPropertiesAnnotationUsed(detail string) Error {
 	return Error{ErrorPropertiesAnnotationUsed, LevelWarn, "", "", detail}
 }
+
+func WarnDeprecatedValidator(detail string) Error {
+	return Error{ErrorDeprecatedValidator, LevelWarn, "", "", detail}
+}
diff --git a/vendor/github.com/operator-framework/api/pkg/validation/internal/operatorhub.go b/vendor/github.com/operator-framework/api/pkg/validation/internal/operatorhub.go
index e82d10287..ea9bc03b5 100644
--- a/vendor/github.com/operator-framework/api/pkg/validation/internal/operatorhub.go
+++ b/vendor/github.com/operator-framework/api/pkg/validation/internal/operatorhub.go
@@ -6,7 +6,6 @@ import (
 	"io/ioutil"
 	"net/mail"
 	"net/url"
-	"os"
 	"path/filepath"
 	"strings"
 
@@ -118,15 +117,9 @@ import (
 // `k8s-version` key is allowed. If informed, it will perform the checks against this specific Kubernetes version where the
 // operator bundle is intend to be used and will raise errors instead of warnings.
 // Currently, this check is capable of verifying the removed APIs only for Kubernetes 1.22 version.
-var OperatorHubValidator interfaces.Validator = interfaces.ValidatorFunc(validateOperatorHub)
-
-var validCapabilities = map[string]struct{}{
-	"Basic Install":     {},
-	"Seamless Upgrades": {},
-	"Full Lifecycle":    {},
-	"Deep Insights":     {},
-	"Auto Pilot":        {},
-}
+//
+// Deprecated: Use OperatorHubV2Validator, StandardCapabilitiesValidator and StandardCategoriesValidator for equivalent validation.
+var OperatorHubValidator interfaces.Validator = interfaces.ValidatorFunc(validateOperatorHubDeprecated)
 
 var validMediatypes = map[string]struct{}{
 	"image/gif":     {},
@@ -135,29 +128,12 @@ var validMediatypes = map[string]struct{}{
 	"image/svg+xml": {},
 }
 
-var validCategories = map[string]struct{}{
-	"AI/Machine Learning":       {},
-	"Application Runtime":       {},
-	"Big Data":                  {},
-	"Cloud Provider":            {},
-	"Developer Tools":           {},
-	"Database":                  {},
-	"Integration & Delivery":    {},
-	"Logging & Tracing":         {},
-	"Monitoring":                {},
-	"Modernization & Migration": {},
-	"Networking":                {},
-	"OpenShift Optional":        {},
-	"Security":                  {},
-	"Storage":                   {},
-	"Streaming & Messaging":     {},
-}
-
 const minKubeVersionWarnMessage = "csv.Spec.minKubeVersion is not informed. It is recommended you provide this information. " +
 	"Otherwise, it would mean that your operator project can be distributed and installed in any cluster version " +
 	"available, which is not necessarily the case for all projects."
 
-func validateOperatorHub(objs ...interface{}) (results []errors.ManifestResult) {
+// Warning: this validator is deprecated in favor of validateOperatorHub()
+func validateOperatorHubDeprecated(objs ...interface{}) (results []errors.ManifestResult) {
 
 	// Obtain the k8s version if informed via the objects an optional
 	k8sVersion := ""
@@ -178,6 +154,11 @@ func validateOperatorHub(objs ...interface{}) (results []errors.ManifestResult)
 		}
 	}
 
+	// Add a deprecation warning to the list so that users are aware this validator is deprecated
+	deprecationResultWarning := errors.ManifestResult{}
+	deprecationResultWarning.Add(errors.WarnDeprecatedValidator(`The "operatorhub" validator is deprecated; for equivalent validation use "operatorhub/v2", "standardcapabilities" and "standardcategories" validators`))
+	results = append(results, deprecationResultWarning)
+
 	return results
 }
 
@@ -221,7 +202,8 @@ func validateHubCSVSpec(csv v1alpha1.ClusterServiceVersion) CSVChecks {
 	checks = checkSpecProviderName(checks)
 	checks = checkSpecMaintainers(checks)
 	checks = checkSpecLinks(checks)
-	checks = checkAnnotations(checks)
+	checks = checkCapabilities(checks)
+	checks = checkCategories(checks)
 	checks = checkSpecVersion(checks)
 	checks = checkSpecIcon(checks)
 	checks = checkSpecMinKubeVersion(checks)
@@ -256,46 +238,6 @@ func checkSpecVersion(checks CSVChecks) CSVChecks {
 	return checks
 }
 
-// checkAnnotations will validate the values informed via annotations such as; capabilities and categories
-func checkAnnotations(checks CSVChecks) CSVChecks {
-	if checks.csv.GetAnnotations() == nil {
-		checks.csv.SetAnnotations(make(map[string]string))
-	}
-
-	if capability, ok := checks.csv.ObjectMeta.Annotations["capabilities"]; ok {
-		if _, ok := validCapabilities[capability]; !ok {
-			checks.errs = append(checks.errs, fmt.Errorf("csv.Metadata.Annotations.Capabilities %s is not a valid capabilities level", capability))
-		}
-	}
-
-	if categories, ok := checks.csv.ObjectMeta.Annotations["categories"]; ok {
-		categorySlice := strings.Split(categories, ",")
-
-		// use custom categories for validation if provided
-		customCategoriesPath := os.Getenv("OPERATOR_BUNDLE_CATEGORIES")
-		if customCategoriesPath != "" {
-			customCategories, err := extractCategories(customCategoriesPath)
-			if err != nil {
-				checks.errs = append(checks.errs, fmt.Errorf("could not extract custom categories from categories %#v: %s", customCategories, err))
-			} else {
-				for _, category := range categorySlice {
-					if _, ok := customCategories[strings.TrimSpace(category)]; !ok {
-						checks.errs = append(checks.errs, fmt.Errorf("csv.Metadata.Annotations[\"categories\"] value %s is not in the set of custom categories", category))
-					}
-				}
-			}
-		} else {
-			// use default categories
-			for _, category := range categorySlice {
-				if _, ok := validCategories[strings.TrimSpace(category)]; !ok {
-					checks.errs = append(checks.errs, fmt.Errorf("csv.Metadata.Annotations[\"categories\"] value %s is not in the set of default categories", category))
-				}
-			}
-		}
-	}
-	return checks
-}
-
 // checkSpecIcon will validate if the CSV.spec.Icon was informed and is correct
 func checkSpecIcon(checks CSVChecks) CSVChecks {
 	if checks.csv.Spec.Icon != nil {
diff --git a/vendor/github.com/operator-framework/api/pkg/validation/internal/operatorhubv2.go b/vendor/github.com/operator-framework/api/pkg/validation/internal/operatorhubv2.go
new file mode 100644
index 000000000..64b5aca18
--- /dev/null
+++ b/vendor/github.com/operator-framework/api/pkg/validation/internal/operatorhubv2.go
@@ -0,0 +1,80 @@
+package internal
+
+import (
+	"github.com/operator-framework/api/pkg/manifests"
+	"github.com/operator-framework/api/pkg/operators/v1alpha1"
+	"github.com/operator-framework/api/pkg/validation/errors"
+	interfaces "github.com/operator-framework/api/pkg/validation/interfaces"
+)
+
+var OperatorHubV2Validator interfaces.Validator = interfaces.ValidatorFunc(validateOperatorHubV2)
+
+func validateOperatorHubV2(objs ...interface{}) (results []errors.ManifestResult) {
+	// Obtain the k8s version if informed via the objects an optional
+	k8sVersion := ""
+	for _, obj := range objs {
+		switch obj.(type) {
+		case map[string]string:
+			k8sVersion = obj.(map[string]string)[k8sVersionKey]
+			if len(k8sVersion) > 0 {
+				break
+			}
+		}
+	}
+
+	for _, obj := range objs {
+		switch v := obj.(type) {
+		case *manifests.Bundle:
+			results = append(results, validateBundleOperatorHubV2(v, k8sVersion))
+		}
+	}
+
+	return results
+}
+
+func validateBundleOperatorHubV2(bundle *manifests.Bundle, k8sVersion string) errors.ManifestResult {
+	result := errors.ManifestResult{Name: bundle.Name}
+
+	if bundle == nil {
+		result.Add(errors.ErrInvalidBundle("Bundle is nil", nil))
+		return result
+	}
+
+	if bundle.CSV == nil {
+		result.Add(errors.ErrInvalidBundle("Bundle csv is nil", bundle.Name))
+		return result
+	}
+
+	csvChecksResult := validateHubCSVSpecV2(*bundle.CSV)
+	for _, err := range csvChecksResult.errs {
+		result.Add(errors.ErrInvalidCSV(err.Error(), bundle.CSV.GetName()))
+	}
+	for _, warn := range csvChecksResult.warns {
+		result.Add(errors.WarnInvalidCSV(warn.Error(), bundle.CSV.GetName()))
+	}
+
+	errs, warns := validateDeprecatedAPIS(bundle, k8sVersion)
+	for _, err := range errs {
+		result.Add(errors.ErrFailedValidation(err.Error(), bundle.CSV.GetName()))
+	}
+	for _, warn := range warns {
+		result.Add(errors.WarnFailedValidation(warn.Error(), bundle.CSV.GetName()))
+	}
+
+	return result
+}
+
+// validateHubCSVSpec will check the CSV against the criteria to publish an
+// operator bundle in the OperatorHub.io
+func validateHubCSVSpecV2(csv v1alpha1.ClusterServiceVersion) CSVChecks {
+	checks := CSVChecks{csv: csv, errs: []error{}, warns: []error{}}
+
+	checks = checkSpecProviderName(checks)
+	checks = checkSpecMaintainers(checks)
+	checks = checkSpecLinks(checks)
+	checks = checkSpecVersion(checks)
+	checks = checkSpecIcon(checks)
+	checks = checkSpecMinKubeVersion(checks)
+
+	return checks
+}
diff --git a/vendor/github.com/operator-framework/api/pkg/validation/internal/standardcapabilities.go b/vendor/github.com/operator-framework/api/pkg/validation/internal/standardcapabilities.go
new file mode 100644
index 000000000..432bb5316
--- /dev/null
+++ b/vendor/github.com/operator-framework/api/pkg/validation/internal/standardcapabilities.go
@@ -0,0 +1,59 @@
+package internal
+
+import (
+	"fmt"
+
+	"github.com/operator-framework/api/pkg/manifests"
+	"github.com/operator-framework/api/pkg/validation/errors"
+	interfaces "github.com/operator-framework/api/pkg/validation/interfaces"
+)
+
+var StandardCapabilitiesValidator interfaces.Validator = interfaces.ValidatorFunc(validateCapabilities)
+
+var validCapabilities = map[string]struct{}{
+	"Basic Install":     {},
+	"Seamless Upgrades": {},
+	"Full Lifecycle":    {},
+	"Deep Insights":     {},
+	"Auto Pilot":        {},
+}
+
+func validateCapabilities(objs ...interface{}) (results []errors.ManifestResult) {
+	for _, obj := range objs {
+		switch v := obj.(type) {
+		case *manifests.Bundle:
+			results = append(results, validateCapabilitiesBundle(v))
+		}
+	}
+
+	return results
+}
+
+func validateCapabilitiesBundle(bundle *manifests.Bundle) errors.ManifestResult {
+	result := errors.ManifestResult{Name: bundle.Name}
+	csvCategoryCheck := CSVChecks{csv: *bundle.CSV, errs: []error{}, warns: []error{}}
+
+	csvChecksResult := checkCapabilities(csvCategoryCheck)
+	for _, err := range csvChecksResult.errs {
+		result.Add(errors.ErrInvalidCSV(err.Error(), bundle.CSV.GetName()))
+	}
+	for _, warn := range csvChecksResult.warns {
+		result.Add(errors.WarnInvalidCSV(warn.Error(), bundle.CSV.GetName()))
+	}
+
+	return result
+}
+
+// checkAnnotations will validate the values informed via annotations such as; capabilities and categories
+func checkCapabilities(checks CSVChecks) CSVChecks {
+	if checks.csv.GetAnnotations() == nil {
+		checks.csv.SetAnnotations(make(map[string]string))
+	}
+
+	if capability, ok := checks.csv.ObjectMeta.Annotations["capabilities"]; ok {
+		if _, ok := validCapabilities[capability]; !ok {
+			checks.errs = append(checks.errs, fmt.Errorf("csv.Metadata.Annotations.Capabilities %q is not a valid capabilities level", capability))
+		}
+	}
+	return checks
+}
diff --git a/vendor/github.com/operator-framework/api/pkg/validation/internal/standardcategories.go b/vendor/github.com/operator-framework/api/pkg/validation/internal/standardcategories.go
new file mode 100644
index 000000000..3b866cf1c
--- /dev/null
+++ b/vendor/github.com/operator-framework/api/pkg/validation/internal/standardcategories.go
@@ -0,0 +1,91 @@
+package internal
+
+import (
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/operator-framework/api/pkg/manifests"
+	"github.com/operator-framework/api/pkg/validation/errors"
+	interfaces "github.com/operator-framework/api/pkg/validation/interfaces"
+)
+
+var StandardCategoriesValidator interfaces.Validator = interfaces.ValidatorFunc(validateCategories)
+
+var validCategories = map[string]struct{}{
+	"AI/Machine Learning":       {},
+	"Application Runtime":       {},
+	"Big Data":                  {},
+	"Cloud Provider":            {},
+	"Developer Tools":           {},
+	"Database":                  {},
+	"Integration & Delivery":    {},
+	"Logging & Tracing":         {},
+	"Monitoring":                {},
+	"Modernization & Migration": {},
+	"Networking":                {},
+	"OpenShift Optional":        {},
+	"Security":                  {},
+	"Storage":                   {},
+	"Streaming & Messaging":     {},
+	"Observability":             {},
+}
+
+func validateCategories(objs ...interface{}) (results []errors.ManifestResult) {
+	for _, obj := range objs {
+		switch v := obj.(type) {
+		case *manifests.Bundle:
+			results = append(results, validateCategoriesBundle(v))
+		}
+	}
+
+	return results
+}
+
+func validateCategoriesBundle(bundle *manifests.Bundle) errors.ManifestResult {
+	result := errors.ManifestResult{Name: bundle.Name}
+	csvCategoryCheck := CSVChecks{csv: *bundle.CSV, errs: []error{}, warns: []error{}}
+
+	csvChecksResult := checkCategories(csvCategoryCheck)
+	for _, err := range csvChecksResult.errs {
+		result.Add(errors.ErrInvalidCSV(err.Error(), bundle.CSV.GetName()))
+	}
+	for _, warn := range csvChecksResult.warns {
+		result.Add(errors.WarnInvalidCSV(warn.Error(), bundle.CSV.GetName()))
+	}
+
+	return result
+}
+
+func checkCategories(checks CSVChecks) CSVChecks {
+	if checks.csv.GetAnnotations() == nil {
+		checks.csv.SetAnnotations(make(map[string]string))
+	}
+
+	if categories, ok := checks.csv.ObjectMeta.Annotations["categories"]; ok {
+		categorySlice := strings.Split(categories, ",")
+
+		// use custom categories for validation if provided
+		customCategoriesPath := os.Getenv("OPERATOR_BUNDLE_CATEGORIES")
+		if customCategoriesPath != "" {
+			customCategories, err := extractCategories(customCategoriesPath)
+			if err != nil {
+				checks.errs = append(checks.errs, fmt.Errorf("could not extract custom categories from categories %#v: %s", customCategories, err))
+			} else {
+				for _, category := range categorySlice {
+					if _, ok := customCategories[strings.TrimSpace(category)]; !ok {
+						checks.errs = append(checks.errs, fmt.Errorf("csv.Metadata.Annotations[\"categories\"] value %q is not in the set of custom categories", category))
+					}
+				}
+			}
+		} else {
+			// use default categories
+			for _, category := range categorySlice {
+				if _, ok := validCategories[strings.TrimSpace(category)]; !ok {
+					checks.errs = append(checks.errs, fmt.Errorf("csv.Metadata.Annotations[\"categories\"] value %q is not in the set of standard categories", category))
+				}
+			}
+		}
+	}
+	return checks
+}
diff --git a/vendor/github.com/operator-framework/api/pkg/validation/validation.go b/vendor/github.com/operator-framework/api/pkg/validation/validation.go
index 2f3f61eab..d98237e05 100644
--- a/vendor/github.com/operator-framework/api/pkg/validation/validation.go
+++ b/vendor/github.com/operator-framework/api/pkg/validation/validation.go
@@ -29,8 +29,23 @@ var BundleValidator = internal.BundleValidator
 
 // OperatorHubValidator implements Validator to validate bundle objects
 // for OperatorHub.io requirements.
+//
+// Deprecated: Use OperatorHubV2Validator, StandardCapabilitiesValidator
+// and StandardCategoriesValidator for equivalent functionality.
 var OperatorHubValidator = internal.OperatorHubValidator
 
+// OperatorHubV2Validator implements Validator to validate bundle objects
+// for OperatorHub.io requirements.
+var OperatorHubV2Validator = internal.OperatorHubV2Validator
+
+// StandardCapabilitiesValidator implements Validator to validate bundle objects
+// for OperatorHub.io requirements around UI capability metadata
+var StandardCapabilitiesValidator = internal.StandardCapabilitiesValidator
+
+// StandardCategoriesValidator implements Validator to validate bundle objects
+// for OperatorHub.io requirements around UI category metadata
+var StandardCategoriesValidator = internal.StandardCategoriesValidator
+
 // Object Validator validates various custom objects in the bundle like PDBs and SCCs.
 // Object validation is optional and not a default-level validation.
 var ObjectValidator = internal.ObjectValidator
@@ -69,7 +84,9 @@ var AllValidators = interfaces.Validators{
 	ClusterServiceVersionValidator,
 	CustomResourceDefinitionValidator,
 	BundleValidator,
-	OperatorHubValidator,
+	OperatorHubV2Validator,
+	StandardCategoriesValidator,
+	StandardCapabilitiesValidator,
 	ObjectValidator,
 	OperatorGroupValidator,
 	CommunityOperatorValidator,
diff --git a/vendor/github.com/operator-framework/operator-registry/alpha/model/model.go b/vendor/github.com/operator-framework/operator-registry/alpha/model/model.go
index 48861e49c..fe73a3c4c 100644
--- a/vendor/github.com/operator-framework/operator-registry/alpha/model/model.go
+++ b/vendor/github.com/operator-framework/operator-registry/alpha/model/model.go
@@ -16,6 +16,10 @@ import (
 	"github.com/operator-framework/operator-registry/alpha/property"
 )
 
+type Deprecation struct {
+	Message string `json:"message"`
+}
+
 func init() {
 	t := types.NewType("svg", "image/svg+xml")
 	filetype.AddMatcher(t, svg.Is)
@@ -44,6 +48,7 @@ type Package struct {
 	Icon           *Icon
 	DefaultChannel *Channel
 	Channels       map[string]*Channel
+	Deprecation    *Deprecation
 }
 
 func (m *Package) Validate() error {
@@ -84,12 +89,17 @@ func (m *Package) Validate() error {
 	if m.DefaultChannel != nil && !foundDefault {
 		result.subErrors = append(result.subErrors, fmt.Errorf("default channel %q not found in channels list", m.DefaultChannel.Name))
 	}
+
+	if err := m.Deprecation.Validate(); err != nil {
+		result.subErrors = append(result.subErrors, fmt.Errorf("invalid deprecation: %v", err))
+	}
+
 	return result.orNil()
 }
 
 type Icon struct {
-	Data      []byte
-	MediaType string
+	Data      []byte `json:"base64data"`
+	MediaType string `json:"mediatype"`
 }
 
 func (i *Icon) Validate() error {
@@ -131,9 +141,10 @@ func (i *Icon) validateData() error {
 }
 
 type Channel struct {
-	Package *Package
-	Name    string
-	Bundles map[string]*Bundle
+	Package     *Package
+	Name        string
+	Bundles     map[string]*Bundle
+	Deprecation *Deprecation
 	// NOTICE: The field Properties of the type Channel is for internal use only.
 	//   DO NOT use it for any public-facing functionalities.
 	//   This API is in alpha stage and it is subject to change.
@@ -206,6 +217,11 @@ func (c *Channel) Validate() error {
 			result.subErrors = append(result.subErrors, fmt.Errorf("bundle %q not correctly linked to parent channel", b.Name))
 		}
 	}
+
+	if err := c.Deprecation.Validate(); err != nil {
+		result.subErrors = append(result.subErrors, fmt.Errorf("invalid deprecation: %v", err))
+	}
+
 	return result.orNil()
 }
 
@@ -264,6 +280,7 @@ type Bundle struct {
 	SkipRange     string
 	Properties    []property.Property
 	RelatedImages []RelatedImage
+	Deprecation   *Deprecation
 
 	// These fields are present so that we can continue serving
 	// the GRPC API the way packageserver expects us to in a
@@ -318,6 +335,10 @@ func (b *Bundle) Validate() error {
 		result.subErrors = append(result.subErrors, errors.New("bundle image must be set"))
 	}
 
+	if err := b.Deprecation.Validate(); err != nil {
+		result.subErrors = append(result.subErrors, fmt.Errorf("invalid deprecation: %v", err))
+	}
+
 	return result.orNil()
 }
 
@@ -374,3 +395,13 @@ func (m Model) AddBundle(b Bundle) {
 		p.DefaultChannel = b.Channel
 	}
 }
+
+func (d *Deprecation) Validate() error {
+	if d == nil {
+		return nil
+	}
+	if d.Message == "" {
+		return errors.New("message must be set")
+	}
+	return nil
+}
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1/health.pb.go b/vendor/github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1/health.pb.go
index fe77e6574..86d3ee48a 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1/health.pb.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1/health.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.28.0
-// 	protoc        v3.19.4
+// 	protoc-gen-go v1.31.0
+// 	protoc        v4.24.4
 // source: health.proto
 
 package grpc_health_v1
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1/health_grpc.pb.go b/vendor/github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1/health_grpc.pb.go
index e22412003..bc79ccdd7 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1/health_grpc.pb.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1/health_grpc.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 // versions:
-// - protoc-gen-go-grpc v1.2.0
-// - protoc             v3.19.4
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             v4.24.4
 // source: health.proto
 
 package grpc_health_v1
@@ -19,6 +19,10 @@ import (
 // Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
+const (
+	Health_Check_FullMethodName = "/grpc.health.v1.Health/Check"
+)
+
 // HealthClient is the client API for Health service.
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -36,7 +40,7 @@ func NewHealthClient(cc grpc.ClientConnInterface) HealthClient {
 
 func (c *healthClient) Check(ctx context.Context, in *HealthCheckRequest, opts ...grpc.CallOption) (*HealthCheckResponse, error) {
 	out := new(HealthCheckResponse)
-	err := c.cc.Invoke(ctx, "/grpc.health.v1.Health/Check", in, out, opts...)
+	err := c.cc.Invoke(ctx, Health_Check_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -81,7 +85,7 @@ func _Health_Check_Handler(srv interface{}, ctx context.Context, dec func(interf
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/grpc.health.v1.Health/Check",
+		FullMethod: Health_Check_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(HealthServer).Check(ctx, req.(*HealthCheckRequest))
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/model_to_api.go b/vendor/github.com/operator-framework/operator-registry/pkg/api/model_to_api.go
index 1abe1cf6b..e7714713d 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/api/model_to_api.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/model_to_api.go
@@ -52,6 +52,13 @@ func ConvertModelBundleToAPIBundle(b model.Bundle) (*Bundle, error) {
 		}
 	}
 
+	var deprecation *Deprecation
+	if b.Deprecation != nil {
+		deprecation = &Deprecation{
+			Message: b.Deprecation.Message,
+		}
+	}
+
 	apiDeps, err := convertModelPropertiesToAPIDependencies(b.Properties)
 	if err != nil {
 		return nil, fmt.Errorf("convert model properties to api dependencies: %v", err)
@@ -71,6 +78,7 @@ func ConvertModelBundleToAPIBundle(b model.Bundle) (*Bundle, error) {
 		Skips:        b.Skips,
 		CsvJson:      csvJson,
 		Object:       b.Objects,
+		Deprecation:  deprecation,
 	}, nil
 }
 
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.pb.go b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.pb.go
index ab44380ec..826e4674f 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.pb.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.28.0
-// 	protoc        v3.19.4
+// 	protoc-gen-go v1.31.0
+// 	protoc        v4.24.4
 // source: registry.proto
 
 package api
@@ -26,8 +26,9 @@ type Channel struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Name    string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
-	CsvName string `protobuf:"bytes,2,opt,name=csvName,proto3" json:"csvName,omitempty"`
+	Name        string       `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	CsvName     string       `protobuf:"bytes,2,opt,name=csvName,proto3" json:"csvName,omitempty"`
+	Deprecation *Deprecation `protobuf:"bytes,3,opt,name=deprecation,proto3" json:"deprecation,omitempty"`
 }
 
 func (x *Channel) Reset() {
@@ -76,6 +77,13 @@ func (x *Channel) GetCsvName() string {
 	return ""
 }
 
+func (x *Channel) GetDeprecation() *Deprecation {
+	if x != nil {
+		return x.Deprecation
+	}
+	return nil
+}
+
 type PackageName struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -128,9 +136,10 @@ type Package struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Name               string     `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
-	Channels           []*Channel `protobuf:"bytes,2,rep,name=channels,proto3" json:"channels,omitempty"`
-	DefaultChannelName string     `protobuf:"bytes,3,opt,name=defaultChannelName,proto3" json:"defaultChannelName,omitempty"`
+	Name               string       `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Channels           []*Channel   `protobuf:"bytes,2,rep,name=channels,proto3" json:"channels,omitempty"`
+	DefaultChannelName string       `protobuf:"bytes,3,opt,name=defaultChannelName,proto3" json:"defaultChannelName,omitempty"`
+	Deprecation        *Deprecation `protobuf:"bytes,4,opt,name=deprecation,proto3" json:"deprecation,omitempty"`
 }
 
 func (x *Package) Reset() {
@@ -186,6 +195,13 @@ func (x *Package) GetDefaultChannelName() string {
 	return ""
 }
 
+func (x *Package) GetDeprecation() *Deprecation {
+	if x != nil {
+		return x.Deprecation
+	}
+	return nil
+}
+
 type GroupVersionKind struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -386,6 +402,7 @@ type Bundle struct {
 	Properties   []*Property         `protobuf:"bytes,12,rep,name=properties,proto3" json:"properties,omitempty"`
 	Replaces     string              `protobuf:"bytes,13,opt,name=replaces,proto3" json:"replaces,omitempty"`
 	Skips        []string            `protobuf:"bytes,14,rep,name=skips,proto3" json:"skips,omitempty"`
+	Deprecation  *Deprecation        `protobuf:"bytes,15,opt,name=deprecation,proto3" json:"deprecation,omitempty"`
 }
 
 func (x *Bundle) Reset() {
@@ -518,6 +535,13 @@ func (x *Bundle) GetSkips() []string {
 	return nil
 }
 
+func (x *Bundle) GetDeprecation() *Deprecation {
+	if x != nil {
+		return x.Deprecation
+	}
+	return nil
+}
+
 type ChannelEntry struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1153,176 +1177,235 @@ func (x *GetDefaultProviderRequest) GetPlural() string {
 	return ""
 }
 
+type Deprecation struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
+}
+
+func (x *Deprecation) Reset() {
+	*x = Deprecation{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_registry_proto_msgTypes[18]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Deprecation) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Deprecation) ProtoMessage() {}
+
+func (x *Deprecation) ProtoReflect() protoreflect.Message {
+	mi := &file_registry_proto_msgTypes[18]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Deprecation.ProtoReflect.Descriptor instead.
+func (*Deprecation) Descriptor() ([]byte, []int) {
+	return file_registry_proto_rawDescGZIP(), []int{18}
+}
+
+func (x *Deprecation) GetMessage() string {
+	if x != nil {
+		return x.Message
+	}
+	return ""
+}
+
 var File_registry_proto protoreflect.FileDescriptor
 
 var file_registry_proto_rawDesc = []byte{
 	0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x12, 0x03, 0x61, 0x70, 0x69, 0x22, 0x37, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
+	0x12, 0x03, 0x61, 0x70, 0x69, 0x22, 0x6b, 0x0a, 0x07, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
 	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
 	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x21,
-	0x0a, 0x0b, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a,
-	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
-	0x65, 0x22, 0x77, 0x0a, 0x07, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04,
-	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
-	0x12, 0x28, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
-	0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65,
-	0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65,
-	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43,
-	0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x6e, 0x0a, 0x10, 0x47, 0x72,
-	0x6f, 0x75, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x14,
-	0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67,
-	0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12,
-	0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69,
-	0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x22, 0x36, 0x0a, 0x0a, 0x44, 0x65,
-	0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05,
-	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
-	0x75, 0x65, 0x22, 0x34, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x12,
-	0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
-	0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xfc, 0x03, 0x0a, 0x06, 0x42, 0x75, 0x6e,
-	0x64, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a,
-	0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12,
-	0x20, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d,
-	0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x73, 0x76, 0x4a, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x07, 0x63, 0x73, 0x76, 0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f,
-	0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a,
-	0x65, 0x63, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x61, 0x74,
-	0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x50,
-	0x61, 0x74, 0x68, 0x12, 0x39, 0x0a, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x41,
-	0x70, 0x69, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e,
-	0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64,
-	0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x41, 0x70, 0x69, 0x73, 0x12, 0x39,
-	0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x41, 0x70, 0x69, 0x73, 0x18, 0x08,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70,
-	0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x0c, 0x72, 0x65, 0x71,
-	0x75, 0x69, 0x72, 0x65, 0x64, 0x41, 0x70, 0x69, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72,
-	0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73,
-	0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x6b, 0x69, 0x70, 0x52, 0x61, 0x6e, 0x67, 0x65,
-	0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x6b, 0x69, 0x70, 0x52, 0x61, 0x6e, 0x67,
-	0x65, 0x12, 0x33, 0x0a, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65,
-	0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65,
-	0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64,
-	0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72,
-	0x74, 0x69, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69,
-	0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65,
-	0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65,
-	0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65,
-	0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x6b, 0x69, 0x70, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09,
-	0x52, 0x05, 0x73, 0x6b, 0x69, 0x70, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x6e,
-	0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x63, 0x6b,
-	0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70,
-	0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x68,
-	0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a,
-	0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0a, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08,
-	0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
-	0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74,
-	0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x14,
-	0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x22, 0x27, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61,
-	0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
-	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x68, 0x0a,
-	0x10, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x32,
+	0x0a, 0x0b, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x70, 0x72, 0x65, 0x63,
+	0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x22, 0x21, 0x0a, 0x0b, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d,
+	0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x07, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67,
+	0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
+	0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x68,
+	0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x08, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x12,
+	0x2e, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65,
+	0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x64, 0x65, 0x66,
+	0x61, 0x75, 0x6c, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12,
+	0x32, 0x0a, 0x0b, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x70, 0x72, 0x65,
+	0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74,
+	0x69, 0x6f, 0x6e, 0x22, 0x6e, 0x0a, 0x10, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a,
+	0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
+	0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70,
+	0x6c, 0x75, 0x72, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75,
+	0x72, 0x61, 0x6c, 0x22, 0x36, 0x0a, 0x0a, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63,
+	0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x34, 0x0a, 0x08, 0x50,
+	0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x22, 0xb0, 0x04, 0x0a, 0x06, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07,
+	0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63,
+	0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67,
+	0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63,
+	0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e,
+	0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63,
+	0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x73,
+	0x76, 0x4a, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x73, 0x76,
+	0x4a, 0x73, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x05,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1e, 0x0a, 0x0a,
+	0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0a, 0x62, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x39, 0x0a, 0x0c,
+	0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x41, 0x70, 0x69, 0x73, 0x18, 0x07, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4b, 0x69, 0x6e, 0x64, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x76, 0x69,
+	0x64, 0x65, 0x64, 0x41, 0x70, 0x69, 0x73, 0x12, 0x39, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x69,
+	0x72, 0x65, 0x64, 0x41, 0x70, 0x69, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e,
+	0x61, 0x70, 0x69, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+	0x4b, 0x69, 0x6e, 0x64, 0x52, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x41, 0x70,
+	0x69, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09,
+	0x73, 0x6b, 0x69, 0x70, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x09, 0x73, 0x6b, 0x69, 0x70, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x0c, 0x64, 0x65,
+	0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x0f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63,
+	0x79, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12,
+	0x2d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x0c, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72,
+	0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1a,
+	0x0a, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x6b,
+	0x69, 0x70, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x73, 0x6b, 0x69, 0x70, 0x73,
+	0x12, 0x32, 0x0a, 0x0b, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
+	0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x70, 0x72,
+	0x65, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x22, 0x8e, 0x01, 0x0a, 0x0c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65,
+	0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x63, 0x6b,
+	0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e,
+	0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68,
+	0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x75, 0x6e,
+	0x64, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x62,
+	0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x70,
+	0x6c, 0x61, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x70,
+	0x6c, 0x61, 0x63, 0x65, 0x73, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x63,
+	0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x14, 0x0a, 0x12, 0x4c,
+	0x69, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x22, 0x27, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x68, 0x0a, 0x10, 0x47, 0x65,
+	0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18,
+	0x0a, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e,
+	0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63,
+	0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x73,
+	0x76, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x73, 0x76,
+	0x4e, 0x61, 0x6d, 0x65, 0x22, 0x57, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c,
+	0x65, 0x49, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
 	0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
 	0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63,
 	0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a,
-	0x07, 0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
-	0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x57, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x42, 0x75,
-	0x6e, 0x64, 0x6c, 0x65, 0x49, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20,
-	0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65,
-	0x22, 0x35, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63,
-	0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a,
+	0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x35, 0x0a,
+	0x19, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65,
+	0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x73,
+	0x76, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x73, 0x76,
+	0x4e, 0x61, 0x6d, 0x65, 0x22, 0x6d, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61,
+	0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a,
 	0x07, 0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
-	0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x6d, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x52, 0x65,
-	0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x12, 0x18, 0x0a, 0x07, 0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x07, 0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x6b,
-	0x67, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67,
-	0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e,
-	0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e,
-	0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x74, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c,
-	0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
-	0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
-	0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x6b, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x18, 0x04,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x22, 0x77, 0x0a, 0x19,
-	0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
-	0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f,
-	0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12,
-	0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e,
-	0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a,
-	0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70,
-	0x6c, 0x75, 0x72, 0x61, 0x6c, 0x22, 0x77, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61,
-	0x75, 0x6c, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
-	0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
-	0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
-	0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x32, 0xcf,
-	0x05, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x12, 0x3d, 0x0a, 0x0c, 0x4c,
-	0x69, 0x73, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x17, 0x2e, 0x61, 0x70,
-	0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61,
-	0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x34, 0x0a, 0x0a, 0x47, 0x65,
-	0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47,
-	0x65, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x1a, 0x0c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x22, 0x00,
-	0x12, 0x31, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x15, 0x2e,
-	0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x75, 0x6e, 0x64, 0x6c,
-	0x65, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65,
-	0x46, 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69,
-	0x2e, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x49, 0x6e, 0x43, 0x68, 0x61, 0x6e,
-	0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69,
-	0x2e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x03, 0x88, 0x02, 0x01, 0x12, 0x55, 0x0a, 0x1c,
-	0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65,
-	0x73, 0x54, 0x68, 0x61, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x12, 0x1e, 0x2e, 0x61,
-	0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65,
-	0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61,
-	0x70, 0x69, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22,
-	0x00, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65,
-	0x54, 0x68, 0x61, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x2e, 0x61,
-	0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e,
-	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42,
-	0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x43, 0x68,
+	0x63, 0x73, 0x76, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61,
+	0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d,
+	0x65, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x4e,
+	0x61, 0x6d, 0x65, 0x22, 0x74, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x50, 0x72, 0x6f,
+	0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a,
+	0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72,
+	0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a,
+	0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e,
+	0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x22, 0x77, 0x0a, 0x19, 0x47, 0x65, 0x74,
+	0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07,
+	0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76,
+	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c,
+	0x75, 0x72, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x72,
+	0x61, 0x6c, 0x22, 0x77, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
+	0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
+	0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
+	0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
+	0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b,
+	0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x18, 0x04, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x75, 0x72, 0x61, 0x6c, 0x22, 0x27, 0x0a, 0x0b, 0x44,
+	0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,
+	0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73,
+	0x73, 0x61, 0x67, 0x65, 0x32, 0xcf, 0x05, 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72,
+	0x79, 0x12, 0x3d, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65,
+	0x73, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x61, 0x63, 0x6b,
+	0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x61, 0x70, 0x69,
+	0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x00, 0x30, 0x01,
+	0x12, 0x34, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x16,
+	0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x63,
+	0x6b, 0x61, 0x67, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e,
+	0x64, 0x6c, 0x65, 0x12, 0x15, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e,
+	0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69,
+	0x2e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x13, 0x47, 0x65, 0x74,
+	0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x46, 0x6f, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
+	0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65,
+	0x49, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x03, 0x88,
+	0x02, 0x01, 0x12, 0x55, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
+	0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x54, 0x68, 0x61, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61,
+	0x63, 0x65, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x52,
+	0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x15, 0x47, 0x65, 0x74,
+	0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x54, 0x68, 0x61, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63,
+	0x65, 0x73, 0x12, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c,
+	0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b,
+	0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a,
+	0x1c, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69,
+	0x65, 0x73, 0x54, 0x68, 0x61, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x12, 0x1b, 0x2e,
+	0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
+	0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x70, 0x69,
+	0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x00, 0x30,
+	0x01, 0x12, 0x5b, 0x0a, 0x22, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x68,
 	0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x54, 0x68, 0x61, 0x74,
-	0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x12, 0x1b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65,
-	0x74, 0x41, 0x6c, 0x6c, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71,
-	0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e,
-	0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x5b, 0x0a, 0x22, 0x47,
-	0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45,
-	0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x54, 0x68, 0x61, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64,
-	0x65, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x61, 0x74, 0x65, 0x73,
-	0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x1a, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45,
-	0x6e, 0x74, 0x72, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x4d, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x44,
-	0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x54, 0x68, 0x61, 0x74,
-	0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47,
-	0x65, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65,
-	0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42,
-	0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x42,
-	0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x12, 0x17, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73,
-	0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
-	0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x00, 0x30, 0x01,
-	0x42, 0x07, 0x5a, 0x05, 0x2e, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x33,
+	0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65,
+	0x74, 0x4c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x68,
+	0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x4d,
+	0x0a, 0x1c, 0x47, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0x75, 0x6e, 0x64,
+	0x6c, 0x65, 0x54, 0x68, 0x61, 0x74, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x73, 0x12, 0x1e,
+	0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x50,
+	0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b,
+	0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a,
+	0x0b, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x12, 0x17, 0x2e, 0x61,
+	0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x42, 0x75, 0x6e, 0x64,
+	0x6c, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0x07, 0x5a, 0x05, 0x2e, 0x3b, 0x61, 0x70, 0x69, 0x62,
+	0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -1337,7 +1420,7 @@ func file_registry_proto_rawDescGZIP() []byte {
 	return file_registry_proto_rawDescData
 }
 
-var file_registry_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
+var file_registry_proto_msgTypes = make([]protoimpl.MessageInfo, 19)
 var file_registry_proto_goTypes = []interface{}{
 	(*Channel)(nil),                   // 0: api.Channel
 	(*PackageName)(nil),               // 1: api.PackageName
@@ -1357,38 +1440,42 @@ var file_registry_proto_goTypes = []interface{}{
 	(*GetAllProvidersRequest)(nil),    // 15: api.GetAllProvidersRequest
 	(*GetLatestProvidersRequest)(nil), // 16: api.GetLatestProvidersRequest
 	(*GetDefaultProviderRequest)(nil), // 17: api.GetDefaultProviderRequest
+	(*Deprecation)(nil),               // 18: api.Deprecation
 }
 var file_registry_proto_depIdxs = []int32{
-	0,  // 0: api.Package.channels:type_name -> api.Channel
-	3,  // 1: api.Bundle.providedApis:type_name -> api.GroupVersionKind
-	3,  // 2: api.Bundle.requiredApis:type_name -> api.GroupVersionKind
-	4,  // 3: api.Bundle.dependencies:type_name -> api.Dependency
-	5,  // 4: api.Bundle.properties:type_name -> api.Property
-	8,  // 5: api.Registry.ListPackages:input_type -> api.ListPackageRequest
-	10, // 6: api.Registry.GetPackage:input_type -> api.GetPackageRequest
-	11, // 7: api.Registry.GetBundle:input_type -> api.GetBundleRequest
-	12, // 8: api.Registry.GetBundleForChannel:input_type -> api.GetBundleInChannelRequest
-	13, // 9: api.Registry.GetChannelEntriesThatReplace:input_type -> api.GetAllReplacementsRequest
-	14, // 10: api.Registry.GetBundleThatReplaces:input_type -> api.GetReplacementRequest
-	15, // 11: api.Registry.GetChannelEntriesThatProvide:input_type -> api.GetAllProvidersRequest
-	16, // 12: api.Registry.GetLatestChannelEntriesThatProvide:input_type -> api.GetLatestProvidersRequest
-	17, // 13: api.Registry.GetDefaultBundleThatProvides:input_type -> api.GetDefaultProviderRequest
-	9,  // 14: api.Registry.ListBundles:input_type -> api.ListBundlesRequest
-	1,  // 15: api.Registry.ListPackages:output_type -> api.PackageName
-	2,  // 16: api.Registry.GetPackage:output_type -> api.Package
-	6,  // 17: api.Registry.GetBundle:output_type -> api.Bundle
-	6,  // 18: api.Registry.GetBundleForChannel:output_type -> api.Bundle
-	7,  // 19: api.Registry.GetChannelEntriesThatReplace:output_type -> api.ChannelEntry
-	6,  // 20: api.Registry.GetBundleThatReplaces:output_type -> api.Bundle
-	7,  // 21: api.Registry.GetChannelEntriesThatProvide:output_type -> api.ChannelEntry
-	7,  // 22: api.Registry.GetLatestChannelEntriesThatProvide:output_type -> api.ChannelEntry
-	6,  // 23: api.Registry.GetDefaultBundleThatProvides:output_type -> api.Bundle
-	6,  // 24: api.Registry.ListBundles:output_type -> api.Bundle
-	15, // [15:25] is the sub-list for method output_type
-	5,  // [5:15] is the sub-list for method input_type
-	5,  // [5:5] is the sub-list for extension type_name
-	5,  // [5:5] is the sub-list for extension extendee
-	0,  // [0:5] is the sub-list for field type_name
+	18, // 0: api.Channel.deprecation:type_name -> api.Deprecation
+	0,  // 1: api.Package.channels:type_name -> api.Channel
+	18, // 2: api.Package.deprecation:type_name -> api.Deprecation
+	3,  // 3: api.Bundle.providedApis:type_name -> api.GroupVersionKind
+	3,  // 4: api.Bundle.requiredApis:type_name -> api.GroupVersionKind
+	4,  // 5: api.Bundle.dependencies:type_name -> api.Dependency
+	5,  // 6: api.Bundle.properties:type_name -> api.Property
+	18, // 7: api.Bundle.deprecation:type_name -> api.Deprecation
+	8,  // 8: api.Registry.ListPackages:input_type -> api.ListPackageRequest
+	10, // 9: api.Registry.GetPackage:input_type -> api.GetPackageRequest
+	11, // 10: api.Registry.GetBundle:input_type -> api.GetBundleRequest
+	12, // 11: api.Registry.GetBundleForChannel:input_type -> api.GetBundleInChannelRequest
+	13, // 12: api.Registry.GetChannelEntriesThatReplace:input_type -> api.GetAllReplacementsRequest
+	14, // 13: api.Registry.GetBundleThatReplaces:input_type -> api.GetReplacementRequest
+	15, // 14: api.Registry.GetChannelEntriesThatProvide:input_type -> api.GetAllProvidersRequest
+	16, // 15: api.Registry.GetLatestChannelEntriesThatProvide:input_type -> api.GetLatestProvidersRequest
+	17, // 16: api.Registry.GetDefaultBundleThatProvides:input_type -> api.GetDefaultProviderRequest
+	9,  // 17: api.Registry.ListBundles:input_type -> api.ListBundlesRequest
+	1,  // 18: api.Registry.ListPackages:output_type -> api.PackageName
+	2,  // 19: api.Registry.GetPackage:output_type -> api.Package
+	6,  // 20: api.Registry.GetBundle:output_type -> api.Bundle
+	6,  // 21: api.Registry.GetBundleForChannel:output_type -> api.Bundle
+	7,  // 22: api.Registry.GetChannelEntriesThatReplace:output_type -> api.ChannelEntry
+	6,  // 23: api.Registry.GetBundleThatReplaces:output_type -> api.Bundle
+	7,  // 24: api.Registry.GetChannelEntriesThatProvide:output_type -> api.ChannelEntry
+	7,  // 25: api.Registry.GetLatestChannelEntriesThatProvide:output_type -> api.ChannelEntry
+	6,  // 26: api.Registry.GetDefaultBundleThatProvides:output_type -> api.Bundle
+	6,  // 27: api.Registry.ListBundles:output_type -> api.Bundle
+	18, // [18:28] is the sub-list for method output_type
+	8,  // [8:18] is the sub-list for method input_type
+	8,  // [8:8] is the sub-list for extension type_name
+	8,  // [8:8] is the sub-list for extension extendee
+	0,  // [0:8] is the sub-list for field type_name
 }
 
 func init() { file_registry_proto_init() }
@@ -1613,6 +1700,18 @@ func file_registry_proto_init() {
 				return nil
 			}
 		}
+		file_registry_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Deprecation); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
 	}
 	type x struct{}
 	out := protoimpl.TypeBuilder{
@@ -1620,7 +1719,7 @@ func file_registry_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_registry_proto_rawDesc,
 			NumEnums:      0,
-			NumMessages:   18,
+			NumMessages:   19,
 			NumExtensions: 0,
 			NumServices:   1,
 		},
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto
index 5f1daa9a7..5aa54a253 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry.proto
@@ -22,6 +22,7 @@ service Registry {
 message Channel{
 	string name = 1;
 	string csvName = 2;
+	Deprecation deprecation = 3;
 }
 
 message PackageName{
@@ -32,6 +33,7 @@ message Package{
 	string name = 1;
 	repeated Channel channels = 2;
 	string defaultChannelName = 3;
+	Deprecation deprecation = 4;
 }
 
 message GroupVersionKind{
@@ -66,6 +68,7 @@ message Bundle{
 	repeated Property properties = 12;
 	string replaces = 13;
 	repeated string skips = 14;
+	Deprecation deprecation = 15;
 }
 
 message ChannelEntry{
@@ -124,3 +127,7 @@ message GetDefaultProviderRequest{
 	string kind = 3;
 	string plural = 4;
 }
+
+message Deprecation{
+	string message = 1;
+}
\ No newline at end of file
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry_grpc.pb.go b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry_grpc.pb.go
index 3beb51a51..bd9f08154 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/api/registry_grpc.pb.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/api/registry_grpc.pb.go
@@ -1,7 +1,7 @@
 // Code generated by protoc-gen-go-grpc. DO NOT EDIT.
 // versions:
-// - protoc-gen-go-grpc v1.2.0
-// - protoc             v3.19.4
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             v4.24.4
 // source: registry.proto
 
 package api
@@ -19,6 +19,19 @@ import (
 // Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
+const (
+	Registry_ListPackages_FullMethodName                       = "/api.Registry/ListPackages"
+	Registry_GetPackage_FullMethodName                         = "/api.Registry/GetPackage"
+	Registry_GetBundle_FullMethodName                          = "/api.Registry/GetBundle"
+	Registry_GetBundleForChannel_FullMethodName                = "/api.Registry/GetBundleForChannel"
+	Registry_GetChannelEntriesThatReplace_FullMethodName       = "/api.Registry/GetChannelEntriesThatReplace"
+	Registry_GetBundleThatReplaces_FullMethodName              = "/api.Registry/GetBundleThatReplaces"
+	Registry_GetChannelEntriesThatProvide_FullMethodName       = "/api.Registry/GetChannelEntriesThatProvide"
+	Registry_GetLatestChannelEntriesThatProvide_FullMethodName = "/api.Registry/GetLatestChannelEntriesThatProvide"
+	Registry_GetDefaultBundleThatProvides_FullMethodName       = "/api.Registry/GetDefaultBundleThatProvides"
+	Registry_ListBundles_FullMethodName                        = "/api.Registry/ListBundles"
+)
+
 // RegistryClient is the client API for Registry service.
 //
 // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
@@ -45,7 +58,7 @@ func NewRegistryClient(cc grpc.ClientConnInterface) RegistryClient {
 }
 
 func (c *registryClient) ListPackages(ctx context.Context, in *ListPackageRequest, opts ...grpc.CallOption) (Registry_ListPackagesClient, error) {
-	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[0], "/api.Registry/ListPackages", opts...)
+	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[0], Registry_ListPackages_FullMethodName, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -78,7 +91,7 @@ func (x *registryListPackagesClient) Recv() (*PackageName, error) {
 
 func (c *registryClient) GetPackage(ctx context.Context, in *GetPackageRequest, opts ...grpc.CallOption) (*Package, error) {
 	out := new(Package)
-	err := c.cc.Invoke(ctx, "/api.Registry/GetPackage", in, out, opts...)
+	err := c.cc.Invoke(ctx, Registry_GetPackage_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -87,7 +100,7 @@ func (c *registryClient) GetPackage(ctx context.Context, in *GetPackageRequest,
 
 func (c *registryClient) GetBundle(ctx context.Context, in *GetBundleRequest, opts ...grpc.CallOption) (*Bundle, error) {
 	out := new(Bundle)
-	err := c.cc.Invoke(ctx, "/api.Registry/GetBundle", in, out, opts...)
+	err := c.cc.Invoke(ctx, Registry_GetBundle_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -97,7 +110,7 @@ func (c *registryClient) GetBundle(ctx context.Context, in *GetBundleRequest, op
 // Deprecated: Do not use.
 func (c *registryClient) GetBundleForChannel(ctx context.Context, in *GetBundleInChannelRequest, opts ...grpc.CallOption) (*Bundle, error) {
 	out := new(Bundle)
-	err := c.cc.Invoke(ctx, "/api.Registry/GetBundleForChannel", in, out, opts...)
+	err := c.cc.Invoke(ctx, Registry_GetBundleForChannel_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -105,7 +118,7 @@ func (c *registryClient) GetBundleForChannel(ctx context.Context, in *GetBundleI
 }
 
 func (c *registryClient) GetChannelEntriesThatReplace(ctx context.Context, in *GetAllReplacementsRequest, opts ...grpc.CallOption) (Registry_GetChannelEntriesThatReplaceClient, error) {
-	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[1], "/api.Registry/GetChannelEntriesThatReplace", opts...)
+	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[1], Registry_GetChannelEntriesThatReplace_FullMethodName, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -138,7 +151,7 @@ func (x *registryGetChannelEntriesThatReplaceClient) Recv() (*ChannelEntry, erro
 
 func (c *registryClient) GetBundleThatReplaces(ctx context.Context, in *GetReplacementRequest, opts ...grpc.CallOption) (*Bundle, error) {
 	out := new(Bundle)
-	err := c.cc.Invoke(ctx, "/api.Registry/GetBundleThatReplaces", in, out, opts...)
+	err := c.cc.Invoke(ctx, Registry_GetBundleThatReplaces_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -146,7 +159,7 @@ func (c *registryClient) GetBundleThatReplaces(ctx context.Context, in *GetRepla
 }
 
 func (c *registryClient) GetChannelEntriesThatProvide(ctx context.Context, in *GetAllProvidersRequest, opts ...grpc.CallOption) (Registry_GetChannelEntriesThatProvideClient, error) {
-	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[2], "/api.Registry/GetChannelEntriesThatProvide", opts...)
+	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[2], Registry_GetChannelEntriesThatProvide_FullMethodName, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -178,7 +191,7 @@ func (x *registryGetChannelEntriesThatProvideClient) Recv() (*ChannelEntry, erro
 }
 
 func (c *registryClient) GetLatestChannelEntriesThatProvide(ctx context.Context, in *GetLatestProvidersRequest, opts ...grpc.CallOption) (Registry_GetLatestChannelEntriesThatProvideClient, error) {
-	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[3], "/api.Registry/GetLatestChannelEntriesThatProvide", opts...)
+	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[3], Registry_GetLatestChannelEntriesThatProvide_FullMethodName, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -211,7 +224,7 @@ func (x *registryGetLatestChannelEntriesThatProvideClient) Recv() (*ChannelEntry
 
 func (c *registryClient) GetDefaultBundleThatProvides(ctx context.Context, in *GetDefaultProviderRequest, opts ...grpc.CallOption) (*Bundle, error) {
 	out := new(Bundle)
-	err := c.cc.Invoke(ctx, "/api.Registry/GetDefaultBundleThatProvides", in, out, opts...)
+	err := c.cc.Invoke(ctx, Registry_GetDefaultBundleThatProvides_FullMethodName, in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -219,7 +232,7 @@ func (c *registryClient) GetDefaultBundleThatProvides(ctx context.Context, in *G
 }
 
 func (c *registryClient) ListBundles(ctx context.Context, in *ListBundlesRequest, opts ...grpc.CallOption) (Registry_ListBundlesClient, error) {
-	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[4], "/api.Registry/ListBundles", opts...)
+	stream, err := c.cc.NewStream(ctx, &Registry_ServiceDesc.Streams[4], Registry_ListBundles_FullMethodName, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -346,7 +359,7 @@ func _Registry_GetPackage_Handler(srv interface{}, ctx context.Context, dec func
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/api.Registry/GetPackage",
+		FullMethod: Registry_GetPackage_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(RegistryServer).GetPackage(ctx, req.(*GetPackageRequest))
@@ -364,7 +377,7 @@ func _Registry_GetBundle_Handler(srv interface{}, ctx context.Context, dec func(
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/api.Registry/GetBundle",
+		FullMethod: Registry_GetBundle_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(RegistryServer).GetBundle(ctx, req.(*GetBundleRequest))
@@ -382,7 +395,7 @@ func _Registry_GetBundleForChannel_Handler(srv interface{}, ctx context.Context,
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/api.Registry/GetBundleForChannel",
+		FullMethod: Registry_GetBundleForChannel_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(RegistryServer).GetBundleForChannel(ctx, req.(*GetBundleInChannelRequest))
@@ -421,7 +434,7 @@ func _Registry_GetBundleThatReplaces_Handler(srv interface{}, ctx context.Contex
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/api.Registry/GetBundleThatReplaces",
+		FullMethod: Registry_GetBundleThatReplaces_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(RegistryServer).GetBundleThatReplaces(ctx, req.(*GetReplacementRequest))
@@ -481,7 +494,7 @@ func _Registry_GetDefaultBundleThatProvides_Handler(srv interface{}, ctx context
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/api.Registry/GetDefaultBundleThatProvides",
+		FullMethod: Registry_GetDefaultBundleThatProvides_FullMethodName,
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
 		return srv.(RegistryServer).GetDefaultBundleThatProvides(ctx, req.(*GetDefaultProviderRequest))
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go
index c2c5e42f2..580aeaeb0 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/configmap/configmap_writer.go
@@ -3,7 +3,6 @@ package configmap
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"regexp"
 
@@ -85,7 +84,7 @@ func (c *ConfigMapWriter) Populate(maxDataSizeLimit uint64) error {
 	var totalSize uint64
 	for _, dir := range subDirs {
 		completePath := c.manifestsDir + dir
-		files, err := ioutil.ReadDir(completePath)
+		files, err := os.ReadDir(completePath)
 		if err != nil {
 			logrus.Errorf("read dir failed: %v", err)
 			return err
@@ -95,7 +94,7 @@ func (c *ConfigMapWriter) Populate(maxDataSizeLimit uint64) error {
 			log := logrus.WithField("file", completePath+file.Name())
 			log.Info("Reading file")
 
-			content, err := ioutil.ReadFile(completePath + file.Name())
+			content, err := os.ReadFile(completePath + file.Name())
 			if err != nil {
 				log.Errorf("read failed: %v", err)
 				return err
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/containertools/dockerfilegenerator.go b/vendor/github.com/operator-framework/operator-registry/pkg/containertools/dockerfilegenerator.go
index 2ec06f41d..79059b9ee 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/containertools/dockerfilegenerator.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/containertools/dockerfilegenerator.go
@@ -50,8 +50,8 @@ func (g *IndexDockerfileGenerator) GenerateIndexDockerfile(binarySourceImage, da
 
 	// Content
 	dockerfile += fmt.Sprintf("ADD %s %s\n", databasePath, DefaultDbLocation)
-	dockerfile += fmt.Sprintf("EXPOSE 50051\n")
-	dockerfile += fmt.Sprintf("ENTRYPOINT [\"/bin/opm\"]\n")
+	dockerfile += "EXPOSE 50051\n"
+	dockerfile += "ENTRYPOINT [\"/bin/opm\"]\n"
 	dockerfile += fmt.Sprintf("CMD [\"registry\", \"serve\", \"--database\", \"%s\"]\n", DefaultDbLocation)
 
 	return dockerfile
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/image/mock.go b/vendor/github.com/operator-framework/operator-registry/pkg/image/mock.go
index 6f856c30e..f46d58516 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/image/mock.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/image/mock.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"errors"
 	"io/fs"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sync"
@@ -40,7 +39,7 @@ func (i *MockImage) unpack(dir string) error {
 		if err := os.MkdirAll(pathDir, 0777); err != nil {
 			return err
 		}
-		return ioutil.WriteFile(path, data, 0666)
+		return os.WriteFile(path, data, 0666)
 	})
 }
 
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/chartutil.go b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/chartutil.go
index 42418ce1b..f7090446a 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/chartutil.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/chartutil.go
@@ -19,7 +19,6 @@ limitations under the License.
 package bundle
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -125,7 +124,7 @@ func IsChartDir(dirName string) (bool, error) {
 		return false, errors.Errorf("no %s exists in directory %q", ChartfileName, dirName)
 	}
 
-	chartYamlContent, err := ioutil.ReadFile(chartYaml)
+	chartYamlContent, err := os.ReadFile(chartYaml)
 	if err != nil {
 		return false, errors.Errorf("cannot read %s in directory %q", ChartfileName, dirName)
 	}
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/exporter.go b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/exporter.go
index be9f36312..043aac1ac 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/exporter.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/exporter.go
@@ -2,7 +2,6 @@ package bundle
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -34,7 +33,7 @@ func (i *BundleExporter) Export(skipTLSVerify, plainHTTP bool) error {
 
 	log := logrus.WithField("img", i.image)
 
-	tmpDir, err := ioutil.TempDir("./", "bundle_tmp")
+	tmpDir, err := os.MkdirTemp("./", "bundle_tmp")
 	if err != nil {
 		return err
 	}
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/generate.go b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/generate.go
index 0e480c41a..5b9d82153 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/generate.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/generate.go
@@ -3,7 +3,6 @@ package bundle
 import (
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -180,7 +179,7 @@ func CopyYamlOutput(annotationsContent []byte, manifestDir, outputDir, workingDi
 	}
 
 	// Now, generate the `metadata/` dir and write the annotations
-	file, err := ioutil.ReadFile(filepath.Join(copyDir, MetadataDir, AnnotationsFile))
+	file, err := os.ReadFile(filepath.Join(copyDir, MetadataDir, AnnotationsFile))
 	if os.IsNotExist(err) || overwrite {
 		writeDir := filepath.Join(copyDir, MetadataDir)
 		err = WriteFile(AnnotationsFile, writeDir, annotationsContent)
@@ -209,7 +208,7 @@ func GetMediaType(directory string) (string, error) {
 	k8sFiles := make(map[string]*unstructured.Unstructured)
 
 	// Read all file names in directory
-	items, _ := ioutil.ReadDir(directory)
+	items, _ := os.ReadDir(directory)
 	for _, item := range items {
 		if item.IsDir() {
 			continue
@@ -218,7 +217,7 @@ func GetMediaType(directory string) (string, error) {
 		files = append(files, item.Name())
 
 		fileWithPath := filepath.Join(directory, item.Name())
-		fileBlob, err := ioutil.ReadFile(fileWithPath)
+		fileBlob, err := os.ReadFile(fileWithPath)
 		if err != nil {
 			return "", fmt.Errorf("Unable to read file %s in bundle", fileWithPath)
 		}
@@ -367,7 +366,7 @@ func WriteFile(fileName, directory string, content []byte) error {
 		}
 	}
 	log.Infof("Writing %s in %s", fileName, directory)
-	err := ioutil.WriteFile(filepath.Join(directory, fileName), content, DefaultPermission)
+	err := os.WriteFile(filepath.Join(directory, fileName), content, DefaultPermission)
 	if err != nil {
 		return err
 	}
@@ -376,7 +375,7 @@ func WriteFile(fileName, directory string, content []byte) error {
 
 // copy the contents of a potentially nested manifest dir into an output dir.
 func copyManifestDir(from, to string, overwrite bool) error {
-	fromFiles, err := ioutil.ReadDir(from)
+	fromFiles, err := os.ReadDir(from)
 	if err != nil {
 		return err
 	}
@@ -431,7 +430,11 @@ func copyManifestDir(from, to string, overwrite bool) error {
 			return err
 		}
 
-		err = os.Chmod(toFilePath, fromFile.Mode())
+		info, err := fromFile.Info()
+		if err != nil {
+			return err
+		}
+		err = os.Chmod(toFilePath, info.Mode())
 		if err != nil {
 			return err
 		}
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/validate.go b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/validate.go
index fb8ca0368..a11025c28 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/validate.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/lib/bundle/validate.go
@@ -4,7 +4,7 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 
@@ -79,7 +79,7 @@ func (i imageValidator) ValidateBundleFormat(directory string) error {
 	var metadataDir, manifestsDir string
 	var validationErrors []error
 
-	items, err := ioutil.ReadDir(directory)
+	items, err := os.ReadDir(directory)
 	if err != nil {
 		validationErrors = append(validationErrors, err)
 	}
@@ -118,7 +118,7 @@ func (i imageValidator) ValidateBundleFormat(directory string) error {
 	}
 
 	// Validate annotations file
-	files, err := ioutil.ReadDir(metadataDir)
+	files, err := os.ReadDir(metadataDir)
 	if err != nil {
 		validationErrors = append(validationErrors, err)
 	}
@@ -282,14 +282,14 @@ func (i imageValidator) ValidateBundleContent(manifestDir string) error {
 	crdValidator := v.CustomResourceDefinitionValidator
 
 	// Read all files in manifests directory
-	items, err := ioutil.ReadDir(manifestDir)
+	items, err := os.ReadDir(manifestDir)
 	if err != nil {
 		validationErrors = append(validationErrors, err)
 	}
 
 	for _, item := range items {
 		fileWithPath := filepath.Join(manifestDir, item.Name())
-		data, err := ioutil.ReadFile(fileWithPath)
+		data, err := os.ReadFile(fileWithPath)
 		if err != nil {
 			validationErrors = append(validationErrors, fmt.Errorf("Unable to read file %s in supported types", fileWithPath))
 			continue
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/conversion.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/conversion.go
index fd79b31c2..62bb619f4 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/conversion.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/conversion.go
@@ -16,17 +16,31 @@ func PackageManifestToAPIPackage(manifest *PackageManifest) *api.Package {
 	for _, c := range manifest.Channels {
 		channels = append(channels, PackageChannelToAPIChannel(&c))
 	}
+	var deprecation *api.Deprecation
+	if manifest.Deprecation != nil {
+		deprecation = &api.Deprecation{
+			Message: manifest.Deprecation.Message,
+		}
+	}
 	return &api.Package{
 		Name:               manifest.PackageName,
 		DefaultChannelName: manifest.DefaultChannelName,
 		Channels:           channels,
+		Deprecation:        deprecation,
 	}
 }
 
 func PackageChannelToAPIChannel(channel *PackageChannel) *api.Channel {
+	var deprecation *api.Deprecation
+	if channel.Deprecation != nil {
+		deprecation = &api.Deprecation{
+			Message: channel.Deprecation.Message,
+		}
+	}
 	return &api.Channel{
-		Name:    channel.Name,
-		CsvName: channel.CurrentCSVName,
+		Name:        channel.Name,
+		CsvName:     channel.CurrentCSVName,
+		Deprecation: deprecation,
 	}
 }
 
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/directoryGraphLoader.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/directoryGraphLoader.go
index b639c08b5..a899f01e0 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/directoryGraphLoader.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/directoryGraphLoader.go
@@ -2,7 +2,6 @@ package registry
 
 import (
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -36,7 +35,7 @@ func (c csvs) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
 
 // NewPackageGraphLoaderFromDir takes the root directory of the package in the file system.
 func NewPackageGraphLoaderFromDir(packageDir string) (*DirGraphLoader, error) {
-	_, err := ioutil.ReadDir(packageDir)
+	_, err := os.ReadDir(packageDir)
 	if err != nil {
 		return nil, fmt.Errorf("error reading from %s directory, %v", packageDir, err)
 	}
@@ -71,7 +70,7 @@ func (g *DirGraphLoader) Generate() (*Package, error) {
 
 // loadBundleCsvPathMap loads the CsvNameAndReplaceMap and SortedCSVs in the Package Struct.
 func (g *DirGraphLoader) loadBundleCsvPathMap() error {
-	bundleDirs, err := ioutil.ReadDir(g.PackageDir)
+	bundleDirs, err := os.ReadDir(g.PackageDir)
 	if err != nil {
 		return fmt.Errorf("error reading from %s directory, %v", g.PackageDir, err)
 	}
@@ -156,7 +155,7 @@ func (g *DirGraphLoader) getChannelNodes(channelHeadCsv string) *map[BundleKey]m
 // parsePackageYAMLFile parses the *.package.yaml file and fills the information in Package including name,
 // defaultchannel, and head of all Channels. It returns parsing error if any.
 func (g *DirGraphLoader) parsePackageYAMLFile() (*Package, error) {
-	files, err := ioutil.ReadDir(g.PackageDir)
+	files, err := os.ReadDir(g.PackageDir)
 	if err != nil {
 		return nil, fmt.Errorf("error reading bundle parent directory, %v", err)
 	}
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go b/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go
index cc44e5597..3a5ab6293 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/registry/types.go
@@ -79,6 +79,10 @@ type DefinitionKey struct {
 	Version string `json:"version"`
 }
 
+type Deprecation struct {
+	Message string `json:"message,omitempty" yaml:"message,omitempty"`
+}
+
 // PackageManifest holds information about a package, which is a reference to one (or more)
 // channels under a single package.
 type PackageManifest struct {
@@ -91,7 +95,8 @@ type PackageManifest struct {
 	// DefaultChannelName is, if specified, the name of the default channel for the package. The
 	// default channel will be installed if no other channel is explicitly given. If the package
 	// has a single channel, then that channel is implicitly the default.
-	DefaultChannelName string `json:"defaultChannel" yaml:"defaultChannel"`
+	DefaultChannelName string       `json:"defaultChannel" yaml:"defaultChannel"`
+	Deprecation        *Deprecation `json:"deprecation,omitempty" yaml:"deprecation,omitempty"`
 }
 
 // GetDefaultChannel gets the default channel or returns the only one if there's only one. returns empty string if it
@@ -114,7 +119,8 @@ type PackageChannel struct {
 
 	// CurrentCSVName defines a reference to the CSV holding the version of this package currently
 	// for the channel.
-	CurrentCSVName string `json:"currentCSV" yaml:"currentCSV"`
+	CurrentCSVName string       `json:"currentCSV" yaml:"currentCSV"`
+	Deprecation    *Deprecation `json:"deprecation,omitempty" yaml:"deprecation,omitempty"`
 }
 
 // IsDefaultChannel returns true if the PackageChennel is the default for the PackageManifest
diff --git a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/directory.go b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/directory.go
index f4b2e3e6c..2ed0c595e 100644
--- a/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/directory.go
+++ b/vendor/github.com/operator-framework/operator-registry/pkg/sqlite/directory.go
@@ -2,7 +2,6 @@ package sqlite
 
 import (
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -181,7 +180,7 @@ func (d *DirectoryLoader) LoadPackagesWalkFunc(path string, f os.FileInfo, err e
 // are part of the bundle.
 func loadBundle(csvName string, dir string) (*registry.Bundle, error) {
 	log := logrus.WithFields(logrus.Fields{"dir": dir, "load": "bundle", "name": csvName})
-	files, err := ioutil.ReadDir(dir)
+	files, err := os.ReadDir(dir)
 	if err != nil {
 		return nil, err
 	}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index b8bd2a22e..047d9996c 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -650,7 +650,7 @@ github.com/openshift/client-go/config/informers/externalversions/config/v1alpha1
 github.com/openshift/client-go/config/informers/externalversions/internalinterfaces
 github.com/openshift/client-go/config/listers/config/v1
 github.com/openshift/client-go/config/listers/config/v1alpha1
-# github.com/operator-framework/api v0.18.0
+# github.com/operator-framework/api v0.19.0
 ## explicit; go 1.19
 github.com/operator-framework/api/crds
 github.com/operator-framework/api/pkg/constraints
@@ -668,7 +668,7 @@ github.com/operator-framework/api/pkg/validation
 github.com/operator-framework/api/pkg/validation/errors
 github.com/operator-framework/api/pkg/validation/interfaces
 github.com/operator-framework/api/pkg/validation/internal
-# github.com/operator-framework/operator-registry v1.30.1
+# github.com/operator-framework/operator-registry v1.32.0
 ## explicit; go 1.20
 github.com/operator-framework/operator-registry/alpha/model
 github.com/operator-framework/operator-registry/alpha/property


Test patch:
diff --git a/pkg/controller/install/deployment_test.go b/pkg/controller/install/deployment_test.go
index cceea7deb..2a7c90724 100644
--- a/pkg/controller/install/deployment_test.go
+++ b/pkg/controller/install/deployment_test.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"testing"
 
+	hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	appsv1 "k8s.io/api/apps/v1"
@@ -352,7 +353,11 @@ func TestInstallStrategyDeploymentCheckInstallErrors(t *testing.T) {
 			dep := testDeployment("olm-dep-1", namespace, &mockOwner)
 			dep.Spec.Template.SetAnnotations(map[string]string{"test": "annotation"})
 			dep.Spec.RevisionHistoryLimit = &revisionHistoryLimit
-			dep.SetLabels(labels.CloneAndAddLabel(dep.ObjectMeta.GetLabels(), DeploymentSpecHashLabelKey, HashDeploymentSpec(dep.Spec)))
+			hash, err := hashutil.DeepHashObject(&dep.Spec)
+			if err != nil {
+				t.Fatal(err)
+			}
+			dep.SetLabels(labels.CloneAndAddLabel(dep.ObjectMeta.GetLabels(), DeploymentSpecHashLabelKey, hash))
 			dep.Labels[OLMManagedLabelKey] = OLMManagedLabelValue
 			dep.Status.Conditions = append(dep.Status.Conditions, appsv1.DeploymentCondition{
 				Type:   appsv1.DeploymentAvailable,
@@ -374,7 +379,11 @@ func TestInstallStrategyDeploymentCheckInstallErrors(t *testing.T) {
 			deployment := testDeployment("olm-dep-1", namespace, &mockOwner)
 			deployment.Spec.Template.SetAnnotations(map[string]string{"test": "annotation"})
 			deployment.Spec.RevisionHistoryLimit = &revisionHistoryLimit
-			deployment.SetLabels(labels.CloneAndAddLabel(dep.ObjectMeta.GetLabels(), DeploymentSpecHashLabelKey, HashDeploymentSpec(deployment.Spec)))
+			hash, err = hashutil.DeepHashObject(&deployment.Spec)
+			if err != nil {
+				t.Fatal(err)
+			}
+			deployment.SetLabels(labels.CloneAndAddLabel(dep.ObjectMeta.GetLabels(), DeploymentSpecHashLabelKey, hash))
 			fakeClient.CreateOrUpdateDeploymentReturns(&deployment, tt.createDeploymentErr)
 			defer func() {
 				require.Equal(t, &deployment, fakeClient.CreateOrUpdateDeploymentArgsForCall(0))
diff --git a/pkg/controller/operators/catalog/operator_test.go b/pkg/controller/operators/catalog/operator_test.go
index 4ed98a949..bd906dcf4 100644
--- a/pkg/controller/operators/catalog/operator_test.go
+++ b/pkg/controller/operators/catalog/operator_test.go
@@ -999,7 +999,7 @@ func TestSyncCatalogSources(t *testing.T) {
 			},
 			expectedError: nil,
 			expectedObjs: []runtime.Object{
-				pod(*grpcCatalog),
+				pod(t, *grpcCatalog),
 			},
 		},
 		{
@@ -1007,7 +1007,7 @@ func TestSyncCatalogSources(t *testing.T) {
 			namespace:     "cool-namespace",
 			catalogSource: grpcCatalog,
 			k8sObjs: []runtime.Object{
-				pod(v1alpha1.CatalogSource{
+				pod(t, v1alpha1.CatalogSource{
 					ObjectMeta: metav1.ObjectMeta{
 						Name:      "cool-catalog",
 						Namespace: "cool-namespace",
@@ -1031,7 +1031,7 @@ func TestSyncCatalogSources(t *testing.T) {
 			},
 			expectedError: nil,
 			expectedObjs: []runtime.Object{
-				pod(*grpcCatalog),
+				pod(t, *grpcCatalog),
 			},
 		},
 		{
@@ -1110,7 +1110,7 @@ func TestSyncCatalogSources(t *testing.T) {
 				},
 			}),
 			k8sObjs: []runtime.Object{
-				pod(*grpcCatalog),
+				pod(t, *grpcCatalog),
 				service(grpcCatalog.GetName(), grpcCatalog.GetNamespace()),
 				serviceAccount(grpcCatalog.GetName(), grpcCatalog.GetNamespace(), "", objectReference("init secret")),
 			},
@@ -2119,14 +2119,17 @@ func toManifest(t *testing.T, obj runtime.Object) string {
 	return string(raw)
 }
 
-func pod(s v1alpha1.CatalogSource) *corev1.Pod {
+func pod(t *testing.T, s v1alpha1.CatalogSource) *corev1.Pod {
 	serviceAccount := &corev1.ServiceAccount{
 		ObjectMeta: metav1.ObjectMeta{
 			Namespace: s.GetNamespace(),
 			Name:      s.GetName(),
 		},
 	}
-	pod := reconciler.Pod(&s, "registry-server", "central-opm", "central-util", s.Spec.Image, serviceAccount, s.GetLabels(), s.GetAnnotations(), 5, 10, 1001)
+	pod, err := reconciler.Pod(&s, "registry-server", "central-opm", "central-util", s.Spec.Image, serviceAccount, s.GetLabels(), s.GetAnnotations(), 5, 10, 1001)
+	if err != nil {
+		t.Fatal(err)
+	}
 	ownerutil.AddOwner(pod, &s, false, true)
 	return pod
 }
diff --git a/pkg/controller/operators/olm/operator_test.go b/pkg/controller/operators/olm/operator_test.go
index e6dbe5014..538408db3 100644
--- a/pkg/controller/operators/olm/operator_test.go
+++ b/pkg/controller/operators/olm/operator_test.go
@@ -20,6 +20,7 @@ import (
 
 	"github.com/google/go-cmp/cmp"
 	configfake "github.com/openshift/client-go/config/clientset/versioned/fake"
+	hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash"
 	"github.com/sirupsen/logrus"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -116,8 +117,12 @@ func ownerLabelFromCSV(name, namespace string) map[string]string {
 	}
 }
 
-func addDepSpecHashLabel(labels map[string]string, strategy v1alpha1.NamedInstallStrategy) map[string]string {
-	labels[install.DeploymentSpecHashLabelKey] = install.HashDeploymentSpec(strategy.StrategySpec.DeploymentSpecs[0].Spec)
+func addDepSpecHashLabel(t *testing.T, labels map[string]string, strategy v1alpha1.NamedInstallStrategy) map[string]string {
+	hash, err := hashutil.DeepHashObject(&strategy.StrategySpec.DeploymentSpecs[0].Spec)
+	if err != nil {
+		t.Fatal(err)
+	}
+	labels[install.DeploymentSpecHashLabelKey] = hash
 	return labels
 }
 
@@ -1267,7 +1272,7 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv1-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 				},
 			},
@@ -1313,7 +1318,7 @@ func TestTransitionCSV(t *testing.T) {
 						deployment("a1", namespace, "sa", addAnnotations(defaultTemplateAnnotations, map[string]string{
 							install.OLMCAHashAnnotationKey: validCAHash,
 						})),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(apiServiceInstallStrategy("a1", validCAHash, nil, nil), addAnnotations(defaultTemplateAnnotations, map[string]string{
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(apiServiceInstallStrategy("a1", validCAHash, nil, nil), addAnnotations(defaultTemplateAnnotations, map[string]string{
 							install.OLMCAHashAnnotationKey: validCAHash,
 						}))),
 					),
@@ -2339,7 +2344,7 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv1-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 					deployment("extra-dep", namespace, "sa", nil),
 				},
@@ -2429,7 +2434,7 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv1-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(map[string]string{
+						addDepSpecHashLabel(t, map[string]string{
 							ownerutil.OwnerKey:          "csv1",
 							ownerutil.OwnerNamespaceKey: namespace,
 							ownerutil.OwnerKind:         "ClusterServiceVersion",
@@ -2490,7 +2495,7 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv1-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(map[string]string{
+						addDepSpecHashLabel(t, map[string]string{
 							ownerutil.OwnerKey:          "csv1",
 							ownerutil.OwnerNamespaceKey: namespace,
 							ownerutil.OwnerKind:         "ClusterServiceVersion",
@@ -2572,11 +2577,11 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv1-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 					withLabels(
 						deployment("csv2-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 				},
 			},
@@ -2617,11 +2622,11 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv1-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 					withLabels(
 						deployment("csv2-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 				},
 			},
@@ -2678,15 +2683,15 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv1-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 					withLabels(
 						deployment("csv2-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 					withLabels(
 						deployment("csv3-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv3", namespace), withTemplateAnnotations(installStrategy("csv3-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv3", namespace), withTemplateAnnotations(installStrategy("csv3-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 				},
 			},
@@ -2737,15 +2742,15 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv1-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv1", namespace), withTemplateAnnotations(installStrategy("csv1-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 					withLabels(
 						deployment("csv2-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 					withLabels(
 						deployment("csv3-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv3", namespace), withTemplateAnnotations(installStrategy("csv3-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv3", namespace), withTemplateAnnotations(installStrategy("csv3-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 				},
 			},
@@ -2787,11 +2792,11 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv2-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 					withLabels(
 						deployment("csv3-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv3", namespace), withTemplateAnnotations(installStrategy("csv3-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv3", namespace), withTemplateAnnotations(installStrategy("csv3-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 				},
 			},
@@ -2833,11 +2838,11 @@ func TestTransitionCSV(t *testing.T) {
 				objs: []runtime.Object{
 					withLabels(
 						deployment("csv2-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv2", namespace), withTemplateAnnotations(installStrategy("csv2-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 					withLabels(
 						deployment("csv3-dep1", namespace, "sa", defaultTemplateAnnotations),
-						addDepSpecHashLabel(ownerLabelFromCSV("csv3", namespace), withTemplateAnnotations(installStrategy("csv3-dep1", nil, nil), defaultTemplateAnnotations)),
+						addDepSpecHashLabel(t, ownerLabelFromCSV("csv3", namespace), withTemplateAnnotations(installStrategy("csv3-dep1", nil, nil), defaultTemplateAnnotations)),
 					),
 				},
 			},
@@ -4357,28 +4362,40 @@ func TestSyncOperatorGroups(t *testing.T) {
 	ownedDeployment.Spec.Template.Spec.Containers[0].Env = []corev1.EnvVar{{Name: "OPERATOR_CONDITION_NAME", Value: "csv1"}}
 	ownerutil.AddNonBlockingOwner(ownedDeployment, operatorCSV)
 	deploymentSpec := installStrategy(deploymentName, permissions, nil).StrategySpec.DeploymentSpecs[0].Spec
+	hash, err := hashutil.DeepHashObject(&deploymentSpec)
+	if err != nil {
+		t.Fatal(err)
+	}
 	ownedDeployment.SetLabels(map[string]string{
-		install.DeploymentSpecHashLabelKey: install.HashDeploymentSpec(deploymentSpec),
+		install.DeploymentSpecHashLabelKey: hash,
 	})
 
 	annotatedDeployment := ownedDeployment.DeepCopy()
 	annotatedDeployment.Spec.Template.SetAnnotations(map[string]string{operatorsv1.OperatorGroupTargetsAnnotationKey: operatorNamespace + "," + targetNamespace, operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace})
+	hash, err = hashutil.DeepHashObject(&annotatedDeployment.Spec)
+	if err != nil {
+		t.Fatal(err)
+	}
 	annotatedDeployment.SetLabels(map[string]string{
 		"olm.managed":                      "true",
 		"olm.owner":                        "csv1",
 		"olm.owner.namespace":              "operator-ns",
 		"olm.owner.kind":                   "ClusterServiceVersion",
-		install.DeploymentSpecHashLabelKey: install.HashDeploymentSpec(annotatedDeployment.Spec),
+		install.DeploymentSpecHashLabelKey: hash,
 	})
 
 	annotatedGlobalDeployment := ownedDeployment.DeepCopy()
 	annotatedGlobalDeployment.Spec.Template.SetAnnotations(map[string]string{operatorsv1.OperatorGroupTargetsAnnotationKey: "", operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace})
+	hash, err = hashutil.DeepHashObject(&annotatedGlobalDeployment.Spec)
+	if err != nil {
+		t.Fatal(err)
+	}
 	annotatedGlobalDeployment.SetLabels(map[string]string{
 		"olm.managed":                      "true",
 		"olm.owner":                        "csv1",
 		"olm.owner.namespace":              "operator-ns",
 		"olm.owner.kind":                   "ClusterServiceVersion",
-		install.DeploymentSpecHashLabelKey: install.HashDeploymentSpec(annotatedGlobalDeployment.Spec),
+		install.DeploymentSpecHashLabelKey: hash,
 	})
 
 	role := &rbacv1.Role{
diff --git a/pkg/controller/registry/reconciler/configmap_test.go b/pkg/controller/registry/reconciler/configmap_test.go
index 25a7b31fe..04f764459 100644
--- a/pkg/controller/registry/reconciler/configmap_test.go
+++ b/pkg/controller/registry/reconciler/configmap_test.go
@@ -185,14 +185,22 @@ func validConfigMapCatalogSource(configMap *corev1.ConfigMap) *v1alpha1.CatalogS
 	}
 }
 
-func objectsForCatalogSource(catsrc *v1alpha1.CatalogSource) []runtime.Object {
+func objectsForCatalogSource(t *testing.T, catsrc *v1alpha1.CatalogSource) []runtime.Object {
 	var objs []runtime.Object
 	switch catsrc.Spec.SourceType {
 	case v1alpha1.SourceTypeInternal, v1alpha1.SourceTypeConfigmap:
 		decorated := configMapCatalogSourceDecorator{catsrc, runAsUser}
+		service, err := decorated.Service()
+		if err != nil {
+			t.Fatal(err)
+		}
+		pod, err := decorated.Pod(registryImageName)
+		if err != nil {
+			t.Fatal(err)
+		}
 		objs = clientfake.AddSimpleGeneratedNames(
-			clientfake.AddSimpleGeneratedName(decorated.Pod(registryImageName)),
-			decorated.Service(),
+			clientfake.AddSimpleGeneratedName(pod),
+			service,
 			decorated.ServiceAccount(),
 			decorated.Role(),
 			decorated.RoleBinding(),
@@ -201,9 +209,17 @@ func objectsForCatalogSource(catsrc *v1alpha1.CatalogSource) []runtime.Object {
 		if catsrc.Spec.Image != "" {
 			decorated := grpcCatalogSourceDecorator{CatalogSource: catsrc, createPodAsUser: runAsUser, opmImage: ""}
 			serviceAccount := decorated.ServiceAccount()
+			service, err := decorated.Service()
+			if err != nil {
+				t.Fatal(err)
+			}
+			pod, err := decorated.Pod(serviceAccount)
+			if err != nil {
+				t.Fatal(err)
+			}
 			objs = clientfake.AddSimpleGeneratedNames(
-				decorated.Pod(serviceAccount),
-				decorated.Service(),
+				pod,
+				service,
 				serviceAccount,
 			)
 		}
@@ -314,7 +330,7 @@ func TestConfigMapRegistryReconciler(t *testing.T) {
 			testName: "ExistingRegistry/BadServiceAccount",
 			in: in{
 				cluster: cluster{
-					k8sObjs: append(modifyObjName(objectsForCatalogSource(validCatalogSource), &corev1.ServiceAccount{}, "badName"), validConfigMap),
+					k8sObjs: append(modifyObjName(objectsForCatalogSource(t, validCatalogSource), &corev1.ServiceAccount{}, "badName"), validConfigMap),
 				},
 				catsrc: validCatalogSource,
 			},
@@ -332,7 +348,7 @@ func TestConfigMapRegistryReconciler(t *testing.T) {
 			testName: "ExistingRegistry/BadService",
 			in: in{
 				cluster: cluster{
-					k8sObjs: append(modifyObjName(objectsForCatalogSource(validCatalogSource), &corev1.Service{}, "badName"), validConfigMap),
+					k8sObjs: append(modifyObjName(objectsForCatalogSource(t, validCatalogSource), &corev1.Service{}, "badName"), validConfigMap),
 				},
 				catsrc: validCatalogSource,
 			},
@@ -350,7 +366,7 @@ func TestConfigMapRegistryReconciler(t *testing.T) {
 			testName: "ExistingRegistry/BadServiceWithWrongHash",
 			in: in{
 				cluster: cluster{
-					k8sObjs: append(setLabel(objectsForCatalogSource(validCatalogSource), &corev1.Service{}, ServiceHashLabelKey, "wrongHash"), validConfigMap),
+					k8sObjs: append(setLabel(objectsForCatalogSource(t, validCatalogSource), &corev1.Service{}, ServiceHashLabelKey, "wrongHash"), validConfigMap),
 				},
 				catsrc: validCatalogSource,
 			},
@@ -368,7 +384,7 @@ func TestConfigMapRegistryReconciler(t *testing.T) {
 			testName: "ExistingRegistry/BadPod",
 			in: in{
 				cluster: cluster{
-					k8sObjs: append(setLabel(objectsForCatalogSource(validCatalogSource), &corev1.Pod{}, CatalogSourceLabelKey, "badValue"), validConfigMap),
+					k8sObjs: append(setLabel(objectsForCatalogSource(t, validCatalogSource), &corev1.Pod{}, CatalogSourceLabelKey, "badValue"), validConfigMap),
 				},
 				catsrc: validCatalogSource,
 			},
@@ -386,7 +402,7 @@ func TestConfigMapRegistryReconciler(t *testing.T) {
 			testName: "ExistingRegistry/BadRole",
 			in: in{
 				cluster: cluster{
-					k8sObjs: append(modifyObjName(objectsForCatalogSource(validCatalogSource), &rbacv1.Role{}, "badName"), validConfigMap),
+					k8sObjs: append(modifyObjName(objectsForCatalogSource(t, validCatalogSource), &rbacv1.Role{}, "badName"), validConfigMap),
 				},
 				catsrc: validCatalogSource,
 			},
@@ -404,7 +420,7 @@ func TestConfigMapRegistryReconciler(t *testing.T) {
 			testName: "ExistingRegistry/BadRoleBinding",
 			in: in{
 				cluster: cluster{
-					k8sObjs: append(modifyObjName(objectsForCatalogSource(validCatalogSource), &rbacv1.RoleBinding{}, "badName"), validConfigMap),
+					k8sObjs: append(modifyObjName(objectsForCatalogSource(t, validCatalogSource), &rbacv1.RoleBinding{}, "badName"), validConfigMap),
 				},
 				catsrc: validCatalogSource,
 			},
@@ -422,7 +438,7 @@ func TestConfigMapRegistryReconciler(t *testing.T) {
 			testName: "ExistingRegistry/OldPod",
 			in: in{
 				cluster: cluster{
-					k8sObjs: append(objectsForCatalogSource(validCatalogSource), validConfigMap),
+					k8sObjs: append(objectsForCatalogSource(t, validCatalogSource), validConfigMap),
 				},
 				catsrc: outdatedCatalogSource,
 			},
@@ -457,7 +473,8 @@ func TestConfigMapRegistryReconciler(t *testing.T) {
 			// if no error, the reconciler should create the same set of kube objects every time
 			decorated := configMapCatalogSourceDecorator{tt.in.catsrc, runAsUser}
 
-			pod := decorated.Pod(registryImageName)
+			pod, err := decorated.Pod(registryImageName)
+			require.NoError(t, err)
 			listOptions := metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{CatalogSourceLabelKey: tt.in.catsrc.GetName()}).String()}
 			outPods, err := client.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).List(context.TODO(), listOptions)
 			require.NoError(t, err)
@@ -467,7 +484,8 @@ func TestConfigMapRegistryReconciler(t *testing.T) {
 			require.Equal(t, pod.GetLabels(), outPod.GetLabels())
 			require.Equal(t, pod.Spec, outPod.Spec)
 
-			service := decorated.Service()
+			service, err := decorated.Service()
+			require.NoError(t, err)
 			outService, err := client.KubernetesInterface().CoreV1().Services(service.GetNamespace()).Get(context.TODO(), service.GetName(), metav1.GetOptions{})
 			require.NoError(t, err)
 			require.Equal(t, service, outService)
diff --git a/pkg/controller/registry/reconciler/grpc_test.go b/pkg/controller/registry/reconciler/grpc_test.go
index 5e0513291..33309afdd 100644
--- a/pkg/controller/registry/reconciler/grpc_test.go
+++ b/pkg/controller/registry/reconciler/grpc_test.go
@@ -132,7 +132,7 @@ func TestGrpcRegistryReconciler(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/CreateSuccessful",
 			in: in{
 				cluster: cluster{
-					k8sObjs: objectsForCatalogSource(validGrpcCatalogSource("test-img", "")),
+					k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")),
 				},
 				catsrc: validGrpcCatalogSource("test-img", ""),
 			},
@@ -179,7 +179,7 @@ func TestGrpcRegistryReconciler(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/BadServiceWithWrongHash",
 			in: in{
 				cluster: cluster{
-					k8sObjs: setLabel(objectsForCatalogSource(validGrpcCatalogSource("test-img", "")), &corev1.Service{}, ServiceHashLabelKey, "wrongHash"),
+					k8sObjs: setLabel(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Service{}, ServiceHashLabelKey, "wrongHash"),
 				},
 				catsrc: validGrpcCatalogSource("test-img", ""),
 			},
@@ -197,7 +197,7 @@ func TestGrpcRegistryReconciler(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/BadService",
 			in: in{
 				cluster: cluster{
-					k8sObjs: modifyObjName(objectsForCatalogSource(validGrpcCatalogSource("test-img", "")), &corev1.Service{}, "badName"),
+					k8sObjs: modifyObjName(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Service{}, "badName"),
 				},
 				catsrc: validGrpcCatalogSource("test-img", ""),
 			},
@@ -215,7 +215,7 @@ func TestGrpcRegistryReconciler(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/BadPod",
 			in: in{
 				cluster: cluster{
-					k8sObjs: setLabel(objectsForCatalogSource(validGrpcCatalogSource("test-img", "")), &corev1.Pod{}, CatalogSourceLabelKey, ""),
+					k8sObjs: setLabel(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Pod{}, CatalogSourceLabelKey, ""),
 				},
 				catsrc: validGrpcCatalogSource("test-img", ""),
 			},
@@ -233,7 +233,7 @@ func TestGrpcRegistryReconciler(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/OldPod",
 			in: in{
 				cluster: cluster{
-					k8sObjs: objectsForCatalogSource(validGrpcCatalogSource("old-img", "")),
+					k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("old-img", "")),
 				},
 				catsrc: validGrpcCatalogSource("new-img", ""),
 			},
@@ -320,7 +320,7 @@ func TestGrpcRegistryReconciler(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/UpdateInvalidRegistryServiceStatus",
 			in: in{
 				cluster: cluster{
-					k8sObjs: objectsForCatalogSource(validGrpcCatalogSource("image", "")),
+					k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("image", "")),
 				},
 				catsrc: grpcCatalogSourceWithStatus(v1alpha1.CatalogSourceStatus{
 					RegistryServiceStatus: &v1alpha1.RegistryServiceStatus{
@@ -360,8 +360,14 @@ func TestGrpcRegistryReconciler(t *testing.T) {
 			// Check for resource existence
 			decorated := grpcCatalogSourceDecorator{CatalogSource: tt.in.catsrc, createPodAsUser: runAsUser}
 			sa := decorated.ServiceAccount()
-			pod := decorated.Pod(sa)
-			service := decorated.Service()
+			pod, err := decorated.Pod(sa)
+			if err != nil {
+				t.Fatal(err)
+			}
+			service, err := decorated.Service()
+			if err != nil {
+				t.Fatal(err)
+			}
 			listOptions := metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{CatalogSourceLabelKey: tt.in.catsrc.GetName()}).String()}
 			outPods, podErr := client.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).List(context.TODO(), listOptions)
 			outService, serviceErr := client.KubernetesInterface().CoreV1().Services(service.GetNamespace()).Get(context.TODO(), service.GetName(), metav1.GetOptions{})
@@ -452,7 +458,8 @@ func TestRegistryPodPriorityClass(t *testing.T) {
 
 			// Check for resource existence
 			decorated := grpcCatalogSourceDecorator{CatalogSource: tt.in.catsrc, createPodAsUser: runAsUser}
-			pod := decorated.Pod(serviceAccount(tt.in.catsrc.Namespace, tt.in.catsrc.Name))
+			pod, err := decorated.Pod(serviceAccount(tt.in.catsrc.Namespace, tt.in.catsrc.Name))
+			require.NoError(t, err)
 			listOptions := metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{CatalogSourceLabelKey: tt.in.catsrc.GetName()}).String()}
 			outPods, podErr := client.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).List(context.TODO(), listOptions)
 			require.NoError(t, podErr)
@@ -485,7 +492,7 @@ func TestGrpcRegistryChecker(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/Image/Healthy",
 			in: in{
 				cluster: cluster{
-					k8sObjs: objectsForCatalogSource(validGrpcCatalogSource("test-img", "")),
+					k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")),
 				},
 				catsrc: validGrpcCatalogSource("test-img", ""),
 			},
@@ -506,7 +513,7 @@ func TestGrpcRegistryChecker(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/Image/BadService",
 			in: in{
 				cluster: cluster{
-					k8sObjs: modifyObjName(objectsForCatalogSource(validGrpcCatalogSource("test-img", "")), &corev1.Service{}, "badName"),
+					k8sObjs: modifyObjName(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Service{}, "badName"),
 				},
 				catsrc: validGrpcCatalogSource("test-img", ""),
 			},
@@ -518,7 +525,7 @@ func TestGrpcRegistryChecker(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/Image/BadServiceAccount",
 			in: in{
 				cluster: cluster{
-					k8sObjs: modifyObjName(objectsForCatalogSource(validGrpcCatalogSource("test-img", "")), &corev1.ServiceAccount{}, "badName"),
+					k8sObjs: modifyObjName(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.ServiceAccount{}, "badName"),
 				},
 				catsrc: validGrpcCatalogSource("test-img", ""),
 			},
@@ -530,7 +537,7 @@ func TestGrpcRegistryChecker(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/Image/BadPod",
 			in: in{
 				cluster: cluster{
-					k8sObjs: setLabel(objectsForCatalogSource(validGrpcCatalogSource("test-img", "")), &corev1.Pod{}, CatalogSourceLabelKey, ""),
+					k8sObjs: setLabel(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "")), &corev1.Pod{}, CatalogSourceLabelKey, ""),
 				},
 				catsrc: validGrpcCatalogSource("test-img", ""),
 			},
@@ -542,7 +549,7 @@ func TestGrpcRegistryChecker(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/Image/OldPod/NotHealthy",
 			in: in{
 				cluster: cluster{
-					k8sObjs: objectsForCatalogSource(validGrpcCatalogSource("old-img", "")),
+					k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("old-img", "")),
 				},
 				catsrc: validGrpcCatalogSource("new-img", ""),
 			},
@@ -563,7 +570,7 @@ func TestGrpcRegistryChecker(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/AddressAndImage/Healthy",
 			in: in{
 				cluster: cluster{
-					k8sObjs: objectsForCatalogSource(validGrpcCatalogSource("img-catalog", "catalog.svc.cluster.local:50001")),
+					k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("img-catalog", "catalog.svc.cluster.local:50001")),
 				},
 				catsrc: validGrpcCatalogSource("img-catalog", "catalog.svc.cluster.local:50001"),
 			},
@@ -585,7 +592,7 @@ func TestGrpcRegistryChecker(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/AddressAndImage/BadService/NotHealthy",
 			in: in{
 				cluster: cluster{
-					k8sObjs: modifyObjName(objectsForCatalogSource(validGrpcCatalogSource("test-img", "catalog.svc.cluster.local:50001")), &corev1.Service{}, "badName"),
+					k8sObjs: modifyObjName(objectsForCatalogSource(t, validGrpcCatalogSource("test-img", "catalog.svc.cluster.local:50001")), &corev1.Service{}, "badName"),
 				},
 				catsrc: validGrpcCatalogSource("test-img", "catalog.svc.cluster.local:50001"),
 			},
@@ -597,7 +604,7 @@ func TestGrpcRegistryChecker(t *testing.T) {
 			testName: "Grpc/ExistingRegistry/AddressAndImage/OldPod/NotHealthy",
 			in: in{
 				cluster: cluster{
-					k8sObjs: objectsForCatalogSource(validGrpcCatalogSource("old-img", "catalog.svc.cluster.local:50001")),
+					k8sObjs: objectsForCatalogSource(t, validGrpcCatalogSource("old-img", "catalog.svc.cluster.local:50001")),
 				},
 				catsrc: validGrpcCatalogSource("new-img", "catalog.svc.cluster.local:50001"),
 			},
diff --git a/pkg/controller/registry/reconciler/reconciler_test.go b/pkg/controller/registry/reconciler/reconciler_test.go
index 05b78fedc..abc64e463 100644
--- a/pkg/controller/registry/reconciler/reconciler_test.go
+++ b/pkg/controller/registry/reconciler/reconciler_test.go
@@ -35,7 +35,7 @@ func TestPodMemoryTarget(t *testing.T) {
 				ObjectMeta: metav1.ObjectMeta{
 					GenerateName: "test-",
 					Namespace:    "testns",
-					Labels:       map[string]string{"olm.pod-spec-hash": "68d7885bb7", "olm.managed": "true"},
+					Labels:       map[string]string{"olm.pod-spec-hash": "8SbHWyYfjbRT8lLcfdZ5ofXNdC1GE6ayztILTF", "olm.managed": "true"},
 					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
 				},
 				Spec: corev1.PodSpec{
@@ -107,7 +107,7 @@ func TestPodMemoryTarget(t *testing.T) {
 				ObjectMeta: metav1.ObjectMeta{
 					GenerateName: "test-",
 					Namespace:    "testns",
-					Labels:       map[string]string{"olm.pod-spec-hash": "5c6bb6945f", "olm.managed": "true"},
+					Labels:       map[string]string{"olm.pod-spec-hash": "3DSBhZZIiOl5YIjTsZy9aRyFIXeDR8mZCGAcYA", "olm.managed": "true"},
 					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
 				},
 				Spec: corev1.PodSpec{
@@ -167,7 +167,8 @@ func TestPodMemoryTarget(t *testing.T) {
 	}
 
 	for _, testCase := range testCases {
-		pod := Pod(testCase.input, "name", "opmImage", "utilImage", "image", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+		pod, err := Pod(testCase.input, "name", "opmImage", "utilImage", "image", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+		require.NoError(t, err)
 		if diff := cmp.Diff(pod, testCase.expected); diff != "" {
 			t.Errorf("got incorrect pod: %v", diff)
 		}
@@ -201,7 +202,7 @@ func TestPodExtractContent(t *testing.T) {
 				ObjectMeta: metav1.ObjectMeta{
 					GenerateName: "test-",
 					Namespace:    "testns",
-					Labels:       map[string]string{"olm.pod-spec-hash": "68d7885bb7", "olm.managed": "true"},
+					Labels:       map[string]string{"olm.pod-spec-hash": "8SbHWyYfjbRT8lLcfdZ5ofXNdC1GE6ayztILTF", "olm.managed": "true"},
 					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
 				},
 				Spec: corev1.PodSpec{
@@ -276,7 +277,7 @@ func TestPodExtractContent(t *testing.T) {
 				ObjectMeta: metav1.ObjectMeta{
 					GenerateName: "test-",
 					Namespace:    "testns",
-					Labels:       map[string]string{"olm.pod-spec-hash": "667f4b9769", "olm.managed": "true"},
+					Labels:       map[string]string{"olm.pod-spec-hash": "6AsUxiAHW383luxWxmVVATFBeHXKNIX0HXrP5g", "olm.managed": "true"},
 					Annotations:  map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
 				},
 				Spec: corev1.PodSpec{
@@ -371,7 +372,8 @@ func TestPodExtractContent(t *testing.T) {
 	}
 
 	for _, testCase := range testCases {
-		pod := Pod(testCase.input, "name", "opmImage", "utilImage", "image", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+		pod, err := Pod(testCase.input, "name", "opmImage", "utilImage", "image", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+		require.NoError(t, err)
 		if diff := cmp.Diff(pod, testCase.expected); diff != "" {
 			t.Errorf("got incorrect pod: %v", diff)
 		}
@@ -421,7 +423,8 @@ func TestPodServiceAccountImagePullSecrets(t *testing.T) {
 	}
 
 	for _, testCase := range testCases {
-		pod := Pod(catalogSource, "name", "opmImage", "utilImage", "image", testCase.serviceAccount, map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+		pod, err := Pod(catalogSource, "name", "opmImage", "utilImage", "image", testCase.serviceAccount, map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+		require.NoError(t, err)
 		if diff := cmp.Diff(testCase.serviceAccount.ImagePullSecrets, pod.Spec.ImagePullSecrets); diff != "" {
 			t.Errorf("got incorrect pod: %v", diff)
 		}
@@ -439,7 +442,8 @@ func TestPodNodeSelector(t *testing.T) {
 	key := "kubernetes.io/os"
 	value := "linux"
 
-	gotCatSrcPod := Pod(catsrc, "hello", "utilImage", "opmImage", "busybox", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+	gotCatSrcPod, err := Pod(catsrc, "hello", "utilImage", "opmImage", "busybox", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+	require.NoError(t, err)
 	gotCatSrcPodSelector := gotCatSrcPod.Spec.NodeSelector
 
 	if gotCatSrcPodSelector[key] != value {
@@ -487,7 +491,8 @@ func TestPullPolicy(t *testing.T) {
 	}
 
 	for _, tt := range table {
-		p := Pod(source, "catalog", "opmImage", "utilImage", tt.image, serviceAccount("", "service-account"), nil, nil, int32(0), int32(0), int64(workloadUserID))
+		p, err := Pod(source, "catalog", "opmImage", "utilImage", tt.image, serviceAccount("", "service-account"), nil, nil, int32(0), int32(0), int64(workloadUserID))
+		require.NoError(t, err)
 		policy := p.Spec.Containers[0].ImagePullPolicy
 		if policy != tt.policy {
 			t.Fatalf("expected pull policy %s for image  %s", tt.policy, tt.image)
@@ -599,7 +604,8 @@ func TestPodContainerSecurityContext(t *testing.T) {
 		},
 	}
 	for _, testcase := range testcases {
-		outputPod := Pod(testcase.inputCatsrc, "hello", "utilImage", "opmImage", "busybox", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+		outputPod, err := Pod(testcase.inputCatsrc, "hello", "utilImage", "opmImage", "busybox", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID))
+		require.NoError(t, err)
 		if testcase.expectedSecurityContext != nil {
 			require.Equal(t, testcase.expectedSecurityContext, outputPod.Spec.SecurityContext)
 		}
@@ -629,7 +635,8 @@ func TestPodAvoidsConcurrentWrite(t *testing.T) {
 		"annotation": "somethingelse",
 	}
 
-	gotPod := Pod(catsrc, "hello", "opmImage", "utilImage", "busybox", serviceAccount("", "service-account"), labels, annotations, int32(0), int32(0), int64(workloadUserID))
+	gotPod, err := Pod(catsrc, "hello", "opmImage", "utilImage", "busybox", serviceAccount("", "service-account"), labels, annotations, int32(0), int32(0), int64(workloadUserID))
+	require.NoError(t, err)
 
 	// check labels and annotations point to different addresses between parameters and what's in the pod
 	require.NotEqual(t, &labels, &gotPod.Labels)
@@ -858,7 +865,8 @@ func TestPodSchedulingOverrides(t *testing.T) {
 	}
 
 	for _, testCase := range testCases {
-		pod := Pod(testCase.catalogSource, "hello", "opmImage", "utilImage", "busybox", serviceAccount("", "service-account"), map[string]string{}, testCase.annotations, int32(0), int32(0), int64(workloadUserID))
+		pod, err := Pod(testCase.catalogSource, "hello", "opmImage", "utilImage", "busybox", serviceAccount("", "service-account"), map[string]string{}, testCase.annotations, int32(0), int32(0), int64(workloadUserID))
+		require.NoError(t, err)
 		require.Equal(t, testCase.expectedNodeSelectors, pod.Spec.NodeSelector)
 		require.Equal(t, testCase.expectedPriorityClassName, pod.Spec.PriorityClassName)
 		require.Equal(t, testCase.expectedTolerations, pod.Spec.Tolerations)
diff --git a/pkg/controller/registry/resolver/rbac_test.go b/pkg/controller/registry/resolver/rbac_test.go
index 6f8bd0d4b..9c5f2ee15 100644
--- a/pkg/controller/registry/resolver/rbac_test.go
+++ b/pkg/controller/registry/resolver/rbac_test.go
@@ -31,7 +31,7 @@ func TestGenerateName(t *testing.T) {
 				base: "myname",
 				o:    []string{"something"},
 			},
-			want: "myname-9c895f74f",
+			want: "myname-5L9sNXi3Y6mcOevFzYY3WOLIukKOeZwz1pfUlT",
 		},
 		{
 			name: "truncated",
@@ -39,12 +39,13 @@ func TestGenerateName(t *testing.T) {
 				base: strings.Repeat("name", 100),
 				o:    []string{"something", "else"},
 			},
-			want: "namenamenamenamenamenamenamenamenamenamenamenamename-78fd8b4d6b",
+			want: "namenamenamenamenamename-6XtefCelEzfYlFOD1fARIK5vhWVfWfGHja7H3q",
 		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got := generateName(tt.args.base, tt.args.o)
+			got, err := generateName(tt.args.base, tt.args.o)
+			require.NoError(t, err)
 			require.Equal(t, tt.want, got)
 			require.LessOrEqual(t, len(got), maxNameLength)
 		})
@@ -65,7 +66,8 @@ func (validKubeName) Generate(rand *rand.Rand, size int) reflect.Value {
 
 func TestGeneratesWithinRange(t *testing.T) {
 	f := func(base validKubeName, o string) bool {
-		return len(generateName(string(base), o)) <= maxNameLength
+		out, err := generateName(string(base), o)
+		return len(out) <= maxNameLength || err == nil
 	}
 	require.NoError(t, quick.Check(f, nil))
 }
diff --git a/pkg/package-server/provider/registry_test.go b/pkg/package-server/provider/registry_test.go
index beeb82a74..0f8f8773c 100644
--- a/pkg/package-server/provider/registry_test.go
+++ b/pkg/package-server/provider/registry_test.go
@@ -173,12 +173,13 @@ var (
 
 func TestToPackageManifest(t *testing.T) {
 	tests := []struct {
-		name          string
-		apiPkg        *api.Package
-		catalogSource *operatorsv1alpha1.CatalogSource
-		bundle        *api.Bundle
-		expectedErr   string
-		expected      *operators.PackageManifest
+		name           string
+		apiPkg         *api.Package
+		channelEntries map[string][]operators.ChannelEntry
+		catalogSource  *operatorsv1alpha1.CatalogSource
+		bundle         *api.Bundle
+		expectedErr    string
+		expected       *operators.PackageManifest
 	}{
 		{
 			name: "GoodBundle",
@@ -453,6 +454,364 @@ func TestToPackageManifest(t *testing.T) {
 			},
 			expectedErr: "packagemanifest has no valid channels",
 		},
+		{
+			name: "DeprecatedPackage",
+			apiPkg: &api.Package{
+				Name: "etcd",
+				Channels: []*api.Channel{
+					{
+						Name:    "alpha",
+						CsvName: "etcdoperator.v0.9.2",
+					},
+				},
+				DefaultChannelName: "alpha",
+				Deprecation: &api.Deprecation{
+					Message: "This package is deprecated",
+				},
+			},
+			catalogSource: catalogSource("cool-operators", "ns"),
+			bundle: &api.Bundle{
+				CsvName:     "etcdoperator.v0.9.2",
+				PackageName: "etcd",
+				ChannelName: "alpha",
+				CsvJson:     etcdCSVJSON,
+				Object: []string{
+					etcdCSVJSON,
+					etcdBackupsCRDJSON,
+					etcdUpgradesCRDJSON,
+					etcdRestoresCRDJSON,
+				},
+			},
+			expectedErr: "",
+			expected: &operators.PackageManifest{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "etcd",
+					Namespace: "ns",
+					Labels: labels.Set{
+						"catalog":                         "cool-operators",
+						"catalog-namespace":               "ns",
+						"provider":                        "CoreOS, Inc",
+						"provider-url":                    "",
+						"operatorframework.io/arch.amd64": "supported",
+						"operatorframework.io/os.linux":   "supported",
+					},
+				},
+				Status: operators.PackageManifestStatus{
+					CatalogSource:          "cool-operators",
+					CatalogSourceNamespace: "ns",
+					PackageName:            "etcd",
+					Provider: operators.AppLink{
+						Name: "CoreOS, Inc",
+					},
+					Deprecation: &operators.Deprecation{
+						Message: "This package is deprecated",
+					},
+					DefaultChannel: "alpha",
+					Channels: []operators.PackageChannel{
+						{
+							Name:       "alpha",
+							CurrentCSV: "etcdoperator.v0.9.2",
+							CurrentCSVDesc: func() operators.CSVDescription {
+								csv := operatorsv1alpha1.ClusterServiceVersion{}
+								require.NoError(t, json.Unmarshal([]byte(etcdCSVJSON), &csv))
+								return operators.CreateCSVDescription(&csv, etcdCSVJSON)
+							}(),
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "DeprecatedChannel",
+			apiPkg: &api.Package{
+				Name: "etcd",
+				Channels: []*api.Channel{
+					{
+						Name:    "alpha",
+						CsvName: "etcdoperator.v0.9.2",
+						Deprecation: &api.Deprecation{
+							Message: "This channel of the package is deprecated",
+						},
+					},
+				},
+				DefaultChannelName: "alpha",
+			},
+			catalogSource: catalogSource("cool-operators", "ns"),
+			bundle: &api.Bundle{
+				CsvName:     "etcdoperator.v0.9.2",
+				PackageName: "etcd",
+				ChannelName: "alpha",
+				CsvJson:     etcdCSVJSON,
+				Object: []string{
+					etcdCSVJSON,
+					etcdBackupsCRDJSON,
+					etcdUpgradesCRDJSON,
+					etcdRestoresCRDJSON,
+				},
+			},
+			expectedErr: "",
+			expected: &operators.PackageManifest{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "etcd",
+					Namespace: "ns",
+					Labels: labels.Set{
+						"catalog":                         "cool-operators",
+						"catalog-namespace":               "ns",
+						"provider":                        "CoreOS, Inc",
+						"provider-url":                    "",
+						"operatorframework.io/arch.amd64": "supported",
+						"operatorframework.io/os.linux":   "supported",
+					},
+				},
+				Status: operators.PackageManifestStatus{
+					CatalogSource:          "cool-operators",
+					CatalogSourceNamespace: "ns",
+					PackageName:            "etcd",
+					Provider: operators.AppLink{
+						Name: "CoreOS, Inc",
+					},
+					DefaultChannel: "alpha",
+					Channels: []operators.PackageChannel{
+						{
+							Name: "alpha",
+							Deprecation: &operators.Deprecation{
+								Message: "This channel of the package is deprecated",
+							},
+							CurrentCSV: "etcdoperator.v0.9.2",
+							CurrentCSVDesc: func() operators.CSVDescription {
+								csv := operatorsv1alpha1.ClusterServiceVersion{}
+								require.NoError(t, json.Unmarshal([]byte(etcdCSVJSON), &csv))
+								return operators.CreateCSVDescription(&csv, etcdCSVJSON)
+							}(),
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "DeprecatedEntries",
+			apiPkg: &api.Package{
+				Name: "etcd",
+				Channels: []*api.Channel{
+					{
+						Name:    "alpha",
+						CsvName: "etcdoperator.v0.9.2",
+						Deprecation: &api.Deprecation{
+							Message: "This channel of the package is deprecated",
+						},
+					},
+				},
+				DefaultChannelName: "alpha",
+			},
+			channelEntries: map[string][]operators.ChannelEntry{
+				"alpha": {
+					{
+						Name:    "etcdoperator.v0.9.2",
+						Version: "0.9.2",
+					},
+					{
+						Name:    "etcdoperator.v0.9.0",
+						Version: "0.9.0",
+						Deprecation: &operators.Deprecation{
+							Message: "This bundle of the package is deprecated",
+						},
+					},
+					{
+						Name:    "etcdoperator.v0.6.1",
+						Version: "0.6.1",
+						Deprecation: &operators.Deprecation{
+							Message: "This bundle of the package is also deprecated and has a unique message",
+						},
+					},
+				},
+			},
+			catalogSource: catalogSource("cool-operators", "ns"),
+			bundle: &api.Bundle{
+				CsvName:     "etcdoperator.v0.9.2",
+				PackageName: "etcd",
+				ChannelName: "alpha",
+				CsvJson:     etcdCSVJSON,
+				Object: []string{
+					etcdCSVJSON,
+					etcdBackupsCRDJSON,
+					etcdUpgradesCRDJSON,
+					etcdRestoresCRDJSON,
+				},
+			},
+			expectedErr: "",
+			expected: &operators.PackageManifest{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "etcd",
+					Namespace: "ns",
+					Labels: labels.Set{
+						"catalog":                         "cool-operators",
+						"catalog-namespace":               "ns",
+						"provider":                        "CoreOS, Inc",
+						"provider-url":                    "",
+						"operatorframework.io/arch.amd64": "supported",
+						"operatorframework.io/os.linux":   "supported",
+					},
+				},
+				Status: operators.PackageManifestStatus{
+					CatalogSource:          "cool-operators",
+					CatalogSourceNamespace: "ns",
+					PackageName:            "etcd",
+					Provider: operators.AppLink{
+						Name: "CoreOS, Inc",
+					},
+					DefaultChannel: "alpha",
+					Channels: []operators.PackageChannel{
+						{
+							Name: "alpha",
+							Deprecation: &operators.Deprecation{
+								Message: "This channel of the package is deprecated",
+							},
+							CurrentCSV: "etcdoperator.v0.9.2",
+							CurrentCSVDesc: func() operators.CSVDescription {
+								csv := operatorsv1alpha1.ClusterServiceVersion{}
+								require.NoError(t, json.Unmarshal([]byte(etcdCSVJSON), &csv))
+								return operators.CreateCSVDescription(&csv, etcdCSVJSON)
+							}(),
+							Entries: []operators.ChannelEntry{
+								{
+									Name:    "etcdoperator.v0.9.2",
+									Version: "0.9.2",
+								},
+								{
+									Name:    "etcdoperator.v0.9.0",
+									Version: "0.9.0",
+									Deprecation: &operators.Deprecation{
+										Message: "This bundle of the package is deprecated",
+									},
+								},
+								{
+									Name:    "etcdoperator.v0.6.1",
+									Version: "0.6.1",
+									Deprecation: &operators.Deprecation{
+										Message: "This bundle of the package is also deprecated and has a unique message",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "DeprecatedPackageChannelAndEntries",
+			apiPkg: &api.Package{
+				Name: "etcd",
+				Channels: []*api.Channel{
+					{
+						Name:    "alpha",
+						CsvName: "etcdoperator.v0.9.2",
+						Deprecation: &api.Deprecation{
+							Message: "This channel of the package is deprecated",
+						},
+					},
+				},
+				DefaultChannelName: "alpha",
+				Deprecation: &api.Deprecation{
+					Message: "This package is deprecated",
+				},
+			},
+			channelEntries: map[string][]operators.ChannelEntry{
+				"alpha": {
+					{
+						Name:    "etcdoperator.v0.9.2",
+						Version: "0.9.2",
+					},
+					{
+						Name:    "etcdoperator.v0.9.0",
+						Version: "0.9.0",
+						Deprecation: &operators.Deprecation{
+							Message: "This bundle of the package is deprecated",
+						},
+					},
+					{
+						Name:    "etcdoperator.v0.6.1",
+						Version: "0.6.1",
+						Deprecation: &operators.Deprecation{
+							Message: "This bundle of the package is also deprecated and has a unique message",
+						},
+					},
+				},
+			},
+			catalogSource: catalogSource("cool-operators", "ns"),
+			bundle: &api.Bundle{
+				CsvName:     "etcdoperator.v0.9.2",
+				PackageName: "etcd",
+				ChannelName: "alpha",
+				CsvJson:     etcdCSVJSON,
+				Object: []string{
+					etcdCSVJSON,
+					etcdBackupsCRDJSON,
+					etcdUpgradesCRDJSON,
+					etcdRestoresCRDJSON,
+				},
+			},
+			expectedErr: "",
+			expected: &operators.PackageManifest{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "etcd",
+					Namespace: "ns",
+					Labels: labels.Set{
+						"catalog":                         "cool-operators",
+						"catalog-namespace":               "ns",
+						"provider":                        "CoreOS, Inc",
+						"provider-url":                    "",
+						"operatorframework.io/arch.amd64": "supported",
+						"operatorframework.io/os.linux":   "supported",
+					},
+				},
+				Status: operators.PackageManifestStatus{
+					CatalogSource:          "cool-operators",
+					CatalogSourceNamespace: "ns",
+					PackageName:            "etcd",
+					Provider: operators.AppLink{
+						Name: "CoreOS, Inc",
+					},
+					Deprecation: &operators.Deprecation{
+						Message: "This package is deprecated",
+					},
+					DefaultChannel: "alpha",
+					Channels: []operators.PackageChannel{
+						{
+							Name: "alpha",
+							Deprecation: &operators.Deprecation{
+								Message: "This channel of the package is deprecated",
+							},
+							CurrentCSV: "etcdoperator.v0.9.2",
+							CurrentCSVDesc: func() operators.CSVDescription {
+								csv := operatorsv1alpha1.ClusterServiceVersion{}
+								require.NoError(t, json.Unmarshal([]byte(etcdCSVJSON), &csv))
+								return operators.CreateCSVDescription(&csv, etcdCSVJSON)
+							}(),
+							Entries: []operators.ChannelEntry{
+								{
+									Name:    "etcdoperator.v0.9.2",
+									Version: "0.9.2",
+								},
+								{
+									Name:    "etcdoperator.v0.9.0",
+									Version: "0.9.0",
+									Deprecation: &operators.Deprecation{
+										Message: "This bundle of the package is deprecated",
+									},
+								},
+								{
+									Name:    "etcdoperator.v0.6.1",
+									Version: "0.6.1",
+									Deprecation: &operators.Deprecation{
+										Message: "This bundle of the package is also deprecated and has a unique message",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 	}
 
 	for _, test := range tests {
@@ -465,7 +824,7 @@ func TestToPackageManifest(t *testing.T) {
 				catsrc:         test.catalogSource,
 			}
 
-			packageManifest, err := newPackageManifest(context.Background(), logrus.NewEntry(logrus.New()), test.apiPkg, client, nil)
+			packageManifest, err := newPackageManifest(context.Background(), logrus.NewEntry(logrus.New()), test.apiPkg, client, test.channelEntries)
 			if test.expectedErr != "" {
 				require.Error(t, err)
 				require.Equal(t, test.expectedErr, err.Error())
@@ -1210,6 +1569,160 @@ func TestRegistryProviderList(t *testing.T) {
 				},
 			}},
 		},
+		{
+			name:     "OneCatalog/DeprecatedPackage/DeprecatedChannel/DeprecatedBundle",
+			globalNS: "ns",
+			registryClients: []*registryClient{
+				func() *registryClient {
+					catsrc := catalogSource("cool-operators", "ns")
+
+					listBundlesFake := &fakes.FakeRegistry_ListBundlesClient{}
+					listBundlesFake.RecvReturnsOnCall(0, &api.Bundle{
+						PackageName: "etcd",
+						ChannelName: "alpha",
+						CsvName:     "etcdoperator.v0.9.2",
+						Version:     "0.9.2",
+					}, nil)
+
+					listBundlesFake.RecvReturnsOnCall(1, &api.Bundle{
+						PackageName: "etcd",
+						ChannelName: "deprecated",
+						CsvName:     "etcdoperator.v0.9.2",
+						Version:     "0.9.2",
+						Deprecation: &api.Deprecation{
+							Message: "This version of the package is deprecated",
+						},
+					}, nil)
+					listBundlesFake.RecvReturnsOnCall(2, nil, io.EOF)
+
+					listFake := &fakes.FakeRegistry_ListPackagesClient{}
+					listFake.RecvReturnsOnCall(0, &api.PackageName{Name: "etcd"}, nil)
+					listFake.RecvReturnsOnCall(1, nil, io.EOF)
+
+					clientFake := &fakes.FakeRegistryClient{}
+					clientFake.ListBundlesReturns(listBundlesFake, nil)
+					clientFake.ListPackagesReturns(listFake, nil)
+					clientFake.GetPackageReturnsOnCall(0, &api.Package{
+						Name: "etcd",
+						Deprecation: &api.Deprecation{
+							Message: "This package is deprecated",
+						},
+						Channels: []*api.Channel{
+							{
+								Name:    "alpha",
+								CsvName: "etcdperator.v0.9.2",
+							},
+							{
+								Name:    "deprecated",
+								CsvName: "etcdoperator.v0.9.2",
+								Deprecation: &api.Deprecation{
+									Message: "This channel is deprecated",
+								},
+							},
+						},
+						DefaultChannelName: "alpha",
+					}, nil)
+					clientFake.GetBundleForChannelReturnsOnCall(0, &api.Bundle{
+						CsvName:     "etcdoperator.v0.9.2",
+						PackageName: "etcd",
+						ChannelName: "alpha",
+						CsvJson:     etcdCSVJSON,
+						Object: []string{
+							etcdCSVJSON,
+							etcdBackupsCRDJSON,
+							etcdUpgradesCRDJSON,
+							etcdRestoresCRDJSON,
+						},
+					}, nil)
+
+					clientFake.GetBundleForChannelReturnsOnCall(1, &api.Bundle{
+						CsvName:     "etcdoperator.v0.9.2",
+						PackageName: "etcd",
+						ChannelName: "alpha",
+						CsvJson:     etcdCSVJSON,
+						Object: []string{
+							etcdCSVJSON,
+							etcdBackupsCRDJSON,
+							etcdUpgradesCRDJSON,
+							etcdRestoresCRDJSON,
+						},
+						Deprecation: &api.Deprecation{
+							Message: "This channel is deprecated",
+						},
+					}, nil)
+
+					return &registryClient{clientFake, catsrc, nil}
+				}(),
+			},
+			requestNamespace: "ns",
+			expectedErr:      "",
+			expected: &operators.PackageManifestList{Items: []operators.PackageManifest{
+				{
+					ObjectMeta: metav1.ObjectMeta{
+						Name:      "etcd",
+						Namespace: "ns",
+						Labels: labels.Set{
+							"catalog":                         "cool-operators",
+							"catalog-namespace":               "ns",
+							"provider":                        "CoreOS, Inc",
+							"provider-url":                    "",
+							"operatorframework.io/arch.amd64": "supported",
+							"operatorframework.io/os.linux":   "supported",
+						},
+					},
+					Status: operators.PackageManifestStatus{
+						CatalogSource:          "cool-operators",
+						CatalogSourceNamespace: "ns",
+						PackageName:            "etcd",
+						Provider: operators.AppLink{
+							Name: "CoreOS, Inc",
+						},
+						Deprecation: &operators.Deprecation{
+							Message: "This package is deprecated",
+						},
+						DefaultChannel: "alpha",
+						Channels: []operators.PackageChannel{
+							{
+								Name:       "alpha",
+								CurrentCSV: "etcdoperator.v0.9.2",
+								CurrentCSVDesc: func() operators.CSVDescription {
+									csv := operatorsv1alpha1.ClusterServiceVersion{}
+									require.NoError(t, json.Unmarshal([]byte(etcdCSVJSON), &csv))
+									return operators.CreateCSVDescription(&csv, etcdCSVJSON)
+								}(),
+								Entries: []operators.ChannelEntry{
+									{
+										Name:    "etcdoperator.v0.9.2",
+										Version: "0.9.2",
+									},
+								},
+							},
+							{
+								Name: "deprecated",
+								Entries: []operators.ChannelEntry{
+									{
+										Name:    "etcdoperator.v0.9.2",
+										Version: "0.9.2",
+										Deprecation: &operators.Deprecation{
+											Message: "This version of the package is deprecated",
+										},
+									},
+								},
+								Deprecation: &operators.Deprecation{
+									Message: "This channel is deprecated",
+								},
+								CurrentCSV: "etcdoperator.v0.9.2",
+								CurrentCSVDesc: func() operators.CSVDescription {
+									csv := operatorsv1alpha1.ClusterServiceVersion{}
+									require.NoError(t, json.Unmarshal([]byte(etcdCSVJSON), &csv))
+									return operators.CreateCSVDescription(&csv, etcdCSVJSON)
+								}(),
+							},
+						},
+					},
+				},
+			}},
+		},
 	}
 
 	for _, test := range tests {