Repository: redhat-openshift-ecosystem/openshift-preflight
Pull request #767 (2022-08-18 12:47:33)

Begin usage of operator-framework APIs
The operator-framework API[1] has lots of bundle manipulation tools
that we can leverage to make our own code simpler. This begins the
journey of leveraging those APIs. This removes a good bit of code
that we get from the library.

[1] https://github.com/operator-framework/api

Signed-off-by: Brad P. Crochet <brad@redhat.com>

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

This pull-request has been approved by: *<a href="https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/767#" title="Author self-approved">bcrochet</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=redhat-openshift-ecosystem%2Fopenshift-preflight).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

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

- ~~[OWNERS](https://github.com/redhat-openshift-ecosystem/openshift-preflight/blob/main/OWNERS)~~ [bcrochet]

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":[]} -->
komish: @bcrochet sorry for the extra ping, but is this ready for review? I believe you may have mentioned something about this failing go test in standup, but I can't recall what it was.
bcrochet: > @bcrochet sorry for the extra ping, but is this ready for review? I believe you may have mentioned something about this failing go test in standup, but I can't recall what it was.

Waiting on this: https://github.com/operator-framework/api/pull/255
coveralls: 
[![Coverage Status](https://coveralls.io/builds/51877414/badge)](https://coveralls.io/builds/51877414)

Coverage decreased (-0.3%) to 84.206% when pulling **ae4be7057d9b46213e292792ec021aa0d2ac5249 on bcrochet:validate-api** into **c5b1bce9d1b9379709a6e7b41d705fdb00e6be16 on redhat-openshift-ecosystem:main**.

dcibot: -  FAILURE https://www.distributed-ci.io/jobs/a1b1c193-269d-4b79-8997-fba3949ec140/jobStates
 from https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/767
openshift-ci[bot]: New changes are detected. LGTM label has been removed.
dcibot: -  FAILURE https://www.distributed-ci.io/jobs/c780ade5-ab8f-47fd-86e7-d787db462e38/jobStates
 from https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/767

Patch:
diff --git a/certification/internal/bundle/bundle.go b/certification/internal/bundle/bundle.go
index 7bc0bd5..77797b3 100644
--- a/certification/internal/bundle/bundle.go
+++ b/certification/internal/bundle/bundle.go
@@ -2,7 +2,6 @@ package bundle
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"io"
 	"os"
@@ -12,15 +11,12 @@ import (
 	rbacv1 "k8s.io/api/rbac/v1"
 
 	"github.com/blang/semver"
-	operatorv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
+	"github.com/operator-framework/api/pkg/manifests"
 	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/internal/operatorsdk"
 	log "github.com/sirupsen/logrus"
 	"sigs.k8s.io/yaml"
 )
 
-// versionsKey is the OpenShift versions in annotations.yaml that lists the versions allowed for an operator
-const versionsKey = "com.redhat.openshift.versions"
-
 // This table signifies what the NEXT release of OpenShift will
 // deprecate, not what it matches up to.
 var ocpToKubeVersion = map[string]string{
@@ -54,19 +50,19 @@ func Validate(ctx context.Context, operatorSdk operatorSdk, imagePath string) (*
 	if err != nil {
 		return nil, fmt.Errorf("could not open annotations.yaml: %v", err)
 	}
-	annotations, err := GetAnnotations(ctx, annotationsFile)
+	annotations, err := LoadAnnotations(ctx, annotationsFile)
 	if err != nil {
 		return nil, fmt.Errorf("unable to get annotations.yaml from the bundle: %v", err)
 	}
 
-	if versions, ok := annotations[versionsKey]; ok {
+	if annotations.OpenshiftVersions != "" {
 		// Check that the label range contains >= 4.9
-		targetVersion, err := targetVersion(versions)
+		targetVersion, err := targetVersion(annotations.OpenshiftVersions)
 		if err != nil {
 			// Could not parse the version, which probably means the annotation is invalid
 			return nil, fmt.Errorf("%v", err)
 		}
-		if k8sVer, ok := ocpToKubeVersion[targetVersion]; ok {
+		if k8sVer, found := ocpToKubeVersion[targetVersion]; found {
 			log.Debugf("OpenShift %s detected in annotations. Running with additional checks enabled.", targetVersion)
 			opts.OptionalValues = make(map[string]string)
 			opts.OptionalValues["k8s-version"] = k8sVer
@@ -138,100 +134,33 @@ func cleanStringToGetTheVersionToParse(value string) string {
 	return value
 }
 
-// GetAnnotations accepts a context, and an io.Reader that is expected to provide
-// the annotations.yaml, and parses the annotations from there
-func GetAnnotations(ctx context.Context, r io.Reader) (map[string]string, error) {
-	fileContents, err := io.ReadAll(r)
+// LoadAnnotations reads an operator bundle's annotations.yaml from r.
+func LoadAnnotations(ctx context.Context, r io.Reader) (*Annotations, error) {
+	annFile, err := io.ReadAll(r)
 	if err != nil {
 		return nil, fmt.Errorf("fail to read metadata/annotation.yaml file in bundle: %v", err)
 	}
 
-	annotations, err := ExtractAnnotationsBytes(ctx, fileContents)
-	if err != nil {
-		return nil, fmt.Errorf("metadata/annotations.yaml found but is malformed: %v", err)
-	}
-
-	return annotations, nil
-}
-
-// extractAnnotationsBytes reads the annotation data read from a file and returns the expected format for that yaml
-// represented as a map[string]string.
-func ExtractAnnotationsBytes(ctx context.Context, annotationBytes []byte) (map[string]string, error) {
-	type metadata struct {
-		Annotations map[string]string
-	}
-
-	if len(annotationBytes) == 0 {
-		return nil, errors.New("the annotations file was empty")
-	}
-
-	var bundleMeta metadata
-	if err := yaml.Unmarshal(annotationBytes, &bundleMeta); err != nil {
-		return nil, fmt.Errorf("metadata/annotations.yaml found but is malformed: %v", err)
-	}
-
-	return bundleMeta.Annotations, nil
-}
-
-func GetCsvFilePathFromBundle(imageDir string) (string, error) {
-	log.Trace("reading clusterserviceversion file from the bundle")
-	log.Debug("image directory is ", imageDir)
-	matches, err := filepath.Glob(filepath.Join(imageDir, "manifests", "*.clusterserviceversion.yaml"))
-	if err != nil {
-		return "", fmt.Errorf("glob pattern is malformed: %v", err)
-	}
-	if len(matches) == 0 {
-		return "", fmt.Errorf("unable to find clusterserviceversion file in the bundle image: %v", os.ErrNotExist)
-	}
-	if len(matches) > 1 {
-		return "", fmt.Errorf("more than one CSV file detected in bundle")
-	}
-	log.Debugf("The path to csv file is %s", matches[0])
-	return matches[0], nil
-}
-
-func csvFromReader(ctx context.Context, csvReader io.Reader) (*operatorv1alpha1.ClusterServiceVersion, error) {
-	var csv operatorv1alpha1.ClusterServiceVersion
-	bts, err := io.ReadAll(csvReader)
-	if err != nil {
-		return nil, fmt.Errorf("could not get CSV from reader: %v", err)
-	}
-	err = yaml.Unmarshal(bts, &csv)
-	if err != nil {
-		return nil, fmt.Errorf("malformed CSV detected: %v", err)
+	if len(annFile) == 0 {
+		return nil, fmt.Errorf("annotations file was empty")
 	}
 
-	return &csv, nil
-}
-
-func GetSupportedInstallModes(ctx context.Context, csvReader io.Reader) (map[string]bool, error) {
-	csv, err := csvFromReader(ctx, csvReader)
-	if err != nil {
-		return nil, err
+	var annotationsFile AnnotationsFile
+	if err := yaml.Unmarshal(annFile, &annotationsFile); err != nil {
+		return nil, fmt.Errorf("unable to load the annotations file: %v", err)
 	}
 
-	installedModes := make(map[string]bool, len(csv.Spec.InstallModes))
-	for _, v := range csv.Spec.InstallModes {
-		if v.Supported {
-			installedModes[string(v.Type)] = true
-		}
-	}
-	return installedModes, nil
+	return &annotationsFile.Annotations, nil
 }
 
 // GetSecurityContextConstraints returns an string array of SCC resource names requested by the operator as specified
 // in the csv
-func GetSecurityContextConstraints(ctx context.Context, csvReader io.Reader) ([]string, error) {
-	var csv operatorv1alpha1.ClusterServiceVersion
-	bts, err := io.ReadAll(csvReader)
-	if err != nil {
-		return nil, fmt.Errorf("could not get CSV from reader: %v", err)
-	}
-	err = yaml.Unmarshal(bts, &csv)
+func GetSecurityContextConstraints(ctx context.Context, bundlePath string) ([]string, error) {
+	bundle, err := manifests.GetBundleFromDir(bundlePath)
 	if err != nil {
-		return nil, fmt.Errorf("malformed CSV detected: %v", err)
+		return nil, fmt.Errorf("could not get bundle from dir: %s: %v", bundlePath, err)
 	}
-	for _, cp := range csv.Spec.InstallStrategy.StrategySpec.ClusterPermissions {
+	for _, cp := range bundle.CSV.Spec.InstallStrategy.StrategySpec.ClusterPermissions {
 		for _, rule := range cp.Rules {
 			if hasSCCApiGroup(rule) && hasSCCResource(rule) {
 				return rule.ResourceNames, nil
diff --git a/certification/internal/bundle/types.go b/certification/internal/bundle/types.go
new file mode 100644
index 0000000..2402689
--- /dev/null
+++ b/certification/internal/bundle/types.go
@@ -0,0 +1,13 @@
+package bundle
+
+import "github.com/operator-framework/api/pkg/manifests"
+
+type AnnotationsFile struct {
+	Annotations Annotations `json:"annotations" yaml:"annotations"`
+}
+
+type Annotations struct {
+	manifests.Annotations
+
+	OpenshiftVersions string `json:"com.redhat.openshift.versions,omitempty" yaml:"com.redhat.openshift.versions,omitempty"`
+}
diff --git a/certification/internal/policy/operator/default.go b/certification/internal/policy/operator/default.go
index 4f34338..faf2b37 100644
--- a/certification/internal/policy/operator/default.go
+++ b/certification/internal/policy/operator/default.go
@@ -52,10 +52,10 @@ var (
 		"registry.access.redhat.com":        {},
 	}
 
-	prioritizedInstallModes = []string{
-		string(operatorv1alpha1.InstallModeTypeOwnNamespace),
-		string(operatorv1alpha1.InstallModeTypeSingleNamespace),
-		string(operatorv1alpha1.InstallModeTypeMultiNamespace),
-		string(operatorv1alpha1.InstallModeTypeAllNamespaces),
+	prioritizedInstallModes = []operatorv1alpha1.InstallModeType{
+		operatorv1alpha1.InstallModeTypeOwnNamespace,
+		operatorv1alpha1.InstallModeTypeSingleNamespace,
+		operatorv1alpha1.InstallModeTypeMultiNamespace,
+		operatorv1alpha1.InstallModeTypeAllNamespaces,
 	}
 )
diff --git a/certification/internal/policy/operator/deployable_by_olm.go b/certification/internal/policy/operator/deployable_by_olm.go
index e917dd7..b7c5b17 100644
--- a/certification/internal/policy/operator/deployable_by_olm.go
+++ b/certification/internal/policy/operator/deployable_by_olm.go
@@ -11,6 +11,7 @@ import (
 	"sync"
 	"time"
 
+	"github.com/operator-framework/api/pkg/manifests"
 	operatorv1 "github.com/operator-framework/api/pkg/operators/v1"
 	operatorv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
 	corev1 "k8s.io/api/core/v1"
@@ -37,7 +38,7 @@ type operatorData struct {
 	App              string
 	InstallNamespace string
 	TargetNamespace  string
-	InstallModes     map[string]bool
+	InstallModes     map[operatorv1alpha1.InstallModeType]operatorv1alpha1.InstallMode
 	CsvNamespaces    []string
 	InstalledCsv     string
 }
@@ -198,7 +199,7 @@ func (p *DeployableByOlmCheck) operatorMetadata(ctx context.Context, bundleRef c
 	if err != nil {
 		return nil, fmt.Errorf("could not open annotations.yaml: %w", err)
 	}
-	annotations, err := bundle.GetAnnotations(ctx, annotationsFile)
+	annotations, err := bundle.LoadAnnotations(ctx, annotationsFile)
 	if err != nil {
 		return nil, fmt.Errorf("unable to get annotations.yaml from the bundle: %w", err)
 	}
@@ -206,10 +207,7 @@ func (p *DeployableByOlmCheck) operatorMetadata(ctx context.Context, bundleRef c
 	catalogImage := p.indexImage
 
 	// introspect the channel from the bundle.
-	channel, err := annotation(annotations, channelKeyInBundle)
-	if err != nil {
-		return nil, fmt.Errorf("unable to extract channel name from the bundle: %w", err)
-	}
+	channel := annotations.DefaultChannelName
 
 	// The user provided a channel configuration so we will
 	// use that instead of the introspected value.
@@ -217,24 +215,16 @@ func (p *DeployableByOlmCheck) operatorMetadata(ctx context.Context, bundleRef c
 		channel = p.channel
 	}
 
-	packageName, err := annotation(annotations, packageKey)
-	if err != nil {
-		return nil, fmt.Errorf("unable to extract package name from the bundle: %w", err)
-	}
+	packageName := annotations.PackageName
 
-	csvFilepath, err := bundle.GetCsvFilePathFromBundle(bundleRef.ImageFSPath)
+	bundle, err := manifests.GetBundleFromDir(bundleRef.ImageFSPath)
 	if err != nil {
 		return nil, err
 	}
 
-	csvFileReader, err := os.Open(csvFilepath)
-	if err != nil {
-		return nil, err
-	}
-
-	installModes, err := bundle.GetSupportedInstallModes(ctx, csvFileReader)
-	if err != nil {
-		return nil, fmt.Errorf("unable to extract operator install modes from ClusterServiceVersion: %w", err)
+	installModes := make(map[operatorv1alpha1.InstallModeType]operatorv1alpha1.InstallMode)
+	for _, val := range bundle.CSV.Spec.InstallModes {
+		installModes[val.Type] = val
 	}
 
 	return &operatorData{
@@ -352,24 +342,23 @@ func (p *DeployableByOlmCheck) setUp(ctx context.Context, operatorData *operator
 }
 
 func (p *DeployableByOlmCheck) generateOperatorGroupData(operatorData *operatorData) openshift.OperatorGroupData {
-	var installMode string
-	for i := 0; i < len(prioritizedInstallModes); i++ {
-		if _, ok := operatorData.InstallModes[prioritizedInstallModes[i]]; ok {
-			installMode = prioritizedInstallModes[i]
-			break
+	var installMode operatorv1alpha1.InstallModeType
+	for _, v := range prioritizedInstallModes {
+		if operatorData.InstallModes[v].Supported {
+			installMode = operatorData.InstallModes[v].Type
 		}
 	}
 	log.Debugf("The operator install mode is %s", installMode)
 	targetNamespaces := make([]string, 2)
 
 	switch installMode {
-	case string(operatorv1alpha1.InstallModeTypeOwnNamespace):
+	case operatorv1alpha1.InstallModeTypeOwnNamespace:
 		targetNamespaces = []string{operatorData.InstallNamespace}
-	case string(operatorv1alpha1.InstallModeTypeSingleNamespace):
+	case operatorv1alpha1.InstallModeTypeSingleNamespace:
 		targetNamespaces = []string{operatorData.TargetNamespace}
-	case string(operatorv1alpha1.InstallModeTypeMultiNamespace):
+	case operatorv1alpha1.InstallModeTypeMultiNamespace:
 		targetNamespaces = []string{operatorData.TargetNamespace, operatorData.InstallNamespace}
-	case string(operatorv1alpha1.InstallModeTypeAllNamespaces):
+	case operatorv1alpha1.InstallModeTypeAllNamespaces:
 		targetNamespaces = []string{}
 
 	}
diff --git a/certification/internal/policy/operator/scc_info.go b/certification/internal/policy/operator/scc_info.go
index e981364..6087801 100644
--- a/certification/internal/policy/operator/scc_info.go
+++ b/certification/internal/policy/operator/scc_info.go
@@ -3,7 +3,6 @@ package operator
 import (
 	"context"
 	"fmt"
-	"os"
 
 	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/internal/bundle"
 	log "github.com/sirupsen/logrus"
@@ -35,17 +34,7 @@ func (p *securityContextConstraintsInCSV) Validate(ctx context.Context, bundleRe
 }
 
 func (p *securityContextConstraintsInCSV) dataToValidate(ctx context.Context, imagePath string) ([]string, error) {
-	csvFilepath, err := bundle.GetCsvFilePathFromBundle(imagePath)
-	if err != nil {
-		return nil, err
-	}
-
-	csvFileReader, err := os.Open(csvFilepath)
-	if err != nil {
-		return nil, err
-	}
-
-	requestedSccList, err := bundle.GetSecurityContextConstraints(ctx, csvFileReader)
+	requestedSccList, err := bundle.GetSecurityContextConstraints(ctx, imagePath)
 	if err != nil {
 		return nil, fmt.Errorf("unable to extract security context constraints from ClusterServiceVersion: %w", err)
 	}
diff --git a/certification/internal/policy/operator/validate_operator_bundle.go b/certification/internal/policy/operator/validate_operator_bundle.go
index d34649d..3ecd94a 100644
--- a/certification/internal/policy/operator/validate_operator_bundle.go
+++ b/certification/internal/policy/operator/validate_operator_bundle.go
@@ -26,7 +26,7 @@ func NewValidateOperatorBundleCheck(operatorSdk operatorSdk) *ValidateOperatorBu
 
 const ocpVerV1beta1Unsupported = "4.9"
 
-func (p ValidateOperatorBundleCheck) Validate(ctx context.Context, bundleRef certification.ImageReference) (bool, error) {
+func (p *ValidateOperatorBundleCheck) Validate(ctx context.Context, bundleRef certification.ImageReference) (bool, error) {
 	report, err := p.getDataToValidate(ctx, bundleRef.ImageFSPath)
 	if err != nil {
 		return false, fmt.Errorf("error while executing operator-sdk bundle validate: %v", err)
@@ -35,11 +35,11 @@ func (p ValidateOperatorBundleCheck) Validate(ctx context.Context, bundleRef cer
 	return p.validate(ctx, report)
 }
 
-func (p ValidateOperatorBundleCheck) getDataToValidate(ctx context.Context, imagePath string) (*operatorsdk.OperatorSdkBundleValidateReport, error) {
+func (p *ValidateOperatorBundleCheck) getDataToValidate(ctx context.Context, imagePath string) (*operatorsdk.OperatorSdkBundleValidateReport, error) {
 	return bundle.Validate(ctx, p.OperatorSdk, imagePath)
 }
 
-func (p ValidateOperatorBundleCheck) validate(ctx context.Context, report *operatorsdk.OperatorSdkBundleValidateReport) (bool, error) {
+func (p *ValidateOperatorBundleCheck) validate(ctx context.Context, report *operatorsdk.OperatorSdkBundleValidateReport) (bool, error) {
 	if !report.Passed || len(report.Outputs) > 0 {
 		for _, output := range report.Outputs {
 			var logFn func(...interface{})
@@ -57,11 +57,11 @@ func (p ValidateOperatorBundleCheck) validate(ctx context.Context, report *opera
 	return report.Passed, nil
 }
 
-func (p ValidateOperatorBundleCheck) Name() string {
+func (p *ValidateOperatorBundleCheck) Name() string {
 	return "ValidateOperatorBundle"
 }
 
-func (p ValidateOperatorBundleCheck) Metadata() certification.Metadata {
+func (p *ValidateOperatorBundleCheck) Metadata() certification.Metadata {
 	return certification.Metadata{
 		Description:      "Validating Bundle image that checks if it can validate the content and format of the operator bundle",
 		Level:            "best",
@@ -70,7 +70,7 @@ func (p ValidateOperatorBundleCheck) Metadata() certification.Metadata {
 	}
 }
 
-func (p ValidateOperatorBundleCheck) Help() certification.HelpText {
+func (p *ValidateOperatorBundleCheck) Help() certification.HelpText {
 	return certification.HelpText{
 		Message:    "Check ValidateOperatorBundle encountered an error. Please review the preflight.log file for more information.",
 		Suggestion: "Valid bundles are defined by bundle spec, so make sure that this bundle conforms to that spec. More Information: https://github.com/operator-framework/operator-registry/blob/master/docs/design/operator-bundle.md",
diff --git a/certification/pyxis/pyxis.go b/certification/pyxis/pyxis.go
index 675c31b..7678a5e 100644
--- a/certification/pyxis/pyxis.go
+++ b/certification/pyxis/pyxis.go
@@ -299,9 +299,9 @@ func (p *pyxisClient) GetProject(ctx context.Context) (*CertProject, error) {
 }
 
 func (p *pyxisClient) updateProject(ctx context.Context, certProject *CertProject) (*CertProject, error) {
-	// We cannot send the project type to pyxis in a Patch.
-	// Copy the CertProject and strip the Type value to
-	// have omitempty skip the key in the JSON patch.
+	// We cannot send the project type or container type
+	// to pyxis in a Patch. Copy the CertProject and strip type
+	// values to have omitempty skip the key in the JSON patch.
 	patchCertProject := &CertProject{
 		ID:                  certProject.ID,
 		CertificationStatus: certProject.CertificationStatus,
@@ -310,6 +310,7 @@ func (p *pyxisClient) updateProject(ctx context.Context, certProject *CertProjec
 		ProjectStatus:       certProject.ProjectStatus,
 		// Do not copy the Type.
 	}
+	patchCertProject.Container.Type = "" // Truncate this value, too.
 
 	b, err := json.Marshal(patchCertProject)
 	if err != nil {
diff --git a/certification/pyxis/types.go b/certification/pyxis/types.go
index 469786b..6db02cc 100644
--- a/certification/pyxis/types.go
+++ b/certification/pyxis/types.go
@@ -106,8 +106,8 @@ type CertProject struct {
 
 type Container struct {
 	DockerConfigJSON string `json:"docker_config_json,omitempty"`
-	Type             string `json:"type" default:"Containers"` // conditionally required
-	ISVPID           string `json:"isv_pid,omitempty"`         // required
+	Type             string `json:"type,omitempty"`    // conditionally required
+	ISVPID           string `json:"isv_pid,omitempty"` // required
 	Registry         string `json:"registry,omitempty"`
 	Repository       string `json:"repository,omitempty"`
 	OsContentType    string `json:"os_content_type,omitempty"`
diff --git a/go.mod b/go.mod
index 6aecdfa..5de7a82 100644
--- a/go.mod
+++ b/go.mod
@@ -11,7 +11,7 @@ require (
 	github.com/onsi/gomega v1.20.0
 	github.com/openshift/api v0.0.0-20210910062324-a41d3573a3ba
 	github.com/openshift/client-go v0.0.0-20210521082421-73d9475a9142
-	github.com/operator-framework/api v0.15.0
+	github.com/operator-framework/api v0.16.0
 	github.com/operator-framework/operator-manifest-tools v0.2.1
 	github.com/shurcooL/graphql v0.0.0-20220606043923-3cf50f8a0a29
 	github.com/sirupsen/logrus v1.8.1
@@ -105,3 +105,5 @@ require (
 )
 
 replace github.com/knqyf263/go-rpmdb => github.com/opdev/go-rpmdb v0.0.0-20220719131451-751902254f35
+
+replace github.com/operator-framework/api v0.16.0 => github.com/operator-framework/api v0.16.1-0.20220823134246-5f99430d4ec4
diff --git a/go.sum b/go.sum
index 64ef06e..c6deaf2 100644
--- a/go.sum
+++ b/go.sum
@@ -665,8 +665,8 @@ github.com/openshift/build-machinery-go v0.0.0-20210423112049-9415d7ebd33e/go.mo
 github.com/openshift/client-go v0.0.0-20210521082421-73d9475a9142 h1:ZHRIMCFIJN1p9LsJt4HQ+akDrys4PrYnXzOWI5LK03I=
 github.com/openshift/client-go v0.0.0-20210521082421-73d9475a9142/go.mod h1:fjS8r9mqDVsPb5td3NehsNOAWa4uiFkYEfVZioQ2gH0=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/operator-framework/api v0.15.0 h1:4f9i0drtqHj7ykLoHxv92GR43S7MmQHhmFQkfm5YaGI=
-github.com/operator-framework/api v0.15.0/go.mod h1:scnY9xqSeCsOdtJtNoHIXd7OtHZ14gj1hkDA4+DlgLY=
+github.com/operator-framework/api v0.16.1-0.20220823134246-5f99430d4ec4 h1:juST/k+hHmKD/BlZ4GCzeDdxvNsxB4wHlDyfAPYmSrU=
+github.com/operator-framework/api v0.16.1-0.20220823134246-5f99430d4ec4/go.mod h1:kk8xJahHJR3bKqrA+A+1VIrhOTmyV76k+ARv+iV+u1Q=
 github.com/operator-framework/operator-manifest-tools v0.2.1 h1:hD3iyOm2mBItzYhpFFWqU1StkolS4XGvXxRvFO4v3Oo=
 github.com/operator-framework/operator-manifest-tools v0.2.1/go.mod h1:C4AmRDIJiM8WVyGyqoUuK3KlloZr7XqaabKMMKKhHtA=
 github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=


Test patch:
diff --git a/certification/internal/bundle/bundle_test.go b/certification/internal/bundle/bundle_test.go
index acc7d09..f1d35a2 100644
--- a/certification/internal/bundle/bundle_test.go
+++ b/certification/internal/bundle/bundle_test.go
@@ -1,10 +1,10 @@
 package bundle
 
 import (
+	"bytes"
 	"context"
 	"os"
 	"path/filepath"
-	"strings"
 
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
@@ -111,134 +111,16 @@ var _ = Describe("BundleValidateCheck", func() {
 				Expect(report).ToNot(BeNil())
 			})
 		})
-
-		Context("the annotations file has a bad OpenShift version", func() {
-			JustBeforeEach(func() {
-				err := os.WriteFile(filepath.Join(imageRef.ImageFSPath, metadataDir, annotationFilename), []byte(`annotations:
-  com.redhat.openshift.versions: "vfoo"`), 0o644)
-				Expect(err).ToNot(HaveOccurred())
-			})
-			It("should fail", func() {
-				report, err := Validate(context.Background(), fakeEngine, imageRef.ImageFSPath)
-				Expect(err).To(HaveOccurred())
-				Expect(report).To(BeNil())
-			})
-		})
-
-		Context("getting the CSV file from the bundle", func() {
-			var manifestsPath string
-
-			BeforeEach(func() {
-				manifestsPath = filepath.Join(imageRef.ImageFSPath, manifestsDir)
-				err := os.WriteFile(filepath.Join(manifestsPath, clusterServiceVersionFilename), []byte(""), 0o644)
-				Expect(err).ToNot(HaveOccurred())
-			})
-			Context("the CSV is malformed", func() {
-				It("should error", func() {
-					r := strings.NewReader("badcsv::bad")
-					images, err := GetSupportedInstallModes(context.TODO(), r)
-					Expect(err).To(HaveOccurred())
-					Expect(images).To(BeNil())
-				})
-			})
-			Context("the CSV could not be read", func() {
-				It("should error", func() {
-					images, err := GetSupportedInstallModes(context.TODO(), errReader(0))
-					Expect(err).To(HaveOccurred())
-					Expect(images).To(BeNil())
-				})
-			})
-			Context("the CSV exists by itself", func() {
-				It("should return the filename", func() {
-					filename, err := GetCsvFilePathFromBundle(imageRef.ImageFSPath)
-					Expect(err).ToNot(HaveOccurred())
-					Expect(filename).To(Equal(filepath.Join(manifestsPath, clusterServiceVersionFilename)))
-				})
-			})
-			Context("the CSV doesn't exist", func() {
-				JustBeforeEach(func() {
-					err := os.Remove(filepath.Join(manifestsPath, clusterServiceVersionFilename))
-					Expect(err).ToNot(HaveOccurred())
-				})
-				It("should return an error", func() {
-					filename, err := GetCsvFilePathFromBundle(imageRef.ImageFSPath)
-					Expect(err).To(HaveOccurred())
-					Expect(filename).To(Equal(""))
-				})
-			})
-			Context("there is more than one CSV", func() {
-				JustBeforeEach(func() {
-					err := os.WriteFile(filepath.Join(manifestsPath, "otheroperator.clusterserviceversion.yaml"), []byte(""), 0o664)
-					Expect(err).ToNot(HaveOccurred())
-				})
-				It("should return an error", func() {
-					filename, err := GetCsvFilePathFromBundle(imageRef.ImageFSPath)
-					Expect(err).To(HaveOccurred())
-					Expect(filename).To(Equal(""))
-				})
-			})
-			Context("there is a bad mount dir", func() {
-				It("should return an error", func() {
-					filename, err := GetCsvFilePathFromBundle("[]")
-					Expect(err).To(HaveOccurred())
-					Expect(filename).To(Equal(""))
-				})
-			})
-		})
-	})
-
-	Describe("Supported Install Modes", func() {
-		var csv string = `spec:
-  installModes:
-  - supported: true
-    type: OwnNamespace
-  - supported: true
-    type: SingleNamespace
-  - supported: false
-    type: MultiNamespace
-  - supported: true
-    type: AllNamespaces`
-
-		Context("CSV is valid", func() {
-			It("should return a map of 3", func() {
-				installModes, err := GetSupportedInstallModes(context.Background(), strings.NewReader(csv))
-				Expect(err).ToNot(HaveOccurred())
-				Expect(installModes).ToNot(BeNil())
-				Expect(len(installModes)).To(Equal(3))
-				Expect("MultiNamespace").ToNot(BeElementOf(installModes))
-			})
-		})
-
-		Context("reader is not valid", func() {
-			It("should error", func() {
-				installModes, err := GetSupportedInstallModes(context.Background(), errReader(0))
-				Expect(err).To(HaveOccurred())
-				Expect(installModes).To(BeNil())
-			})
-		})
-
-		Context("CSV is invalid", func() {
-			JustBeforeEach(func() {
-				csv = `invalid`
-			})
-			It("should error", func() {
-				installModes, err := GetSupportedInstallModes(context.Background(), strings.NewReader(csv))
-				Expect(err).To(HaveOccurred())
-				Expect(installModes).To(BeNil())
-			})
-		})
 	})
 
 	Describe("While ensuring that container util is working", func() {
 		// tests: extractAnnotationsBytes
 		Context("with an annotations yaml data read from disk", func() {
 			Context("with the correct format", func() {
-				data := []byte("annotations:\n foo: bar")
-
 				It("should properly marshal to a map[string]string", func() {
-					annotations, err := ExtractAnnotationsBytes(context.TODO(), data)
+					annotations, err := LoadAnnotations(context.TODO(), bytes.NewReader([]byte(annotations)))
 					Expect(err).ToNot(HaveOccurred())
-					Expect(annotations["foo"]).To(Equal("bar"))
+					Expect(annotations.DefaultChannelName).To(Equal("testChannel"))
 				})
 			})
 
@@ -246,7 +128,7 @@ var _ = Describe("BundleValidateCheck", func() {
 				data := []byte{}
 
 				It("should return an error", func() {
-					_, err := ExtractAnnotationsBytes(context.TODO(), data)
+					_, err := LoadAnnotations(context.TODO(), bytes.NewReader(data))
 					Expect(err).To(HaveOccurred())
 				})
 			})
@@ -255,14 +137,14 @@ var _ = Describe("BundleValidateCheck", func() {
 				data := []byte(`malformed`)
 
 				It("should return an error", func() {
-					_, err := ExtractAnnotationsBytes(context.TODO(), data)
+					_, err := LoadAnnotations(context.TODO(), bytes.NewReader(data))
 					Expect(err).To(HaveOccurred())
 				})
 			})
 
 			Context("a bad reader is sent to GetAnnotations", func() {
 				It("should return an error", func() {
-					annotations, err := GetAnnotations(context.Background(), errReader(0))
+					annotations, err := LoadAnnotations(context.TODO(), errReader(0))
 					Expect(err).To(HaveOccurred())
 					Expect(annotations).To(BeNil())
 				})
diff --git a/certification/internal/policy/operator/deployable_by_olm_test.go b/certification/internal/policy/operator/deployable_by_olm_test.go
index 9bbd668..73e0855 100644
--- a/certification/internal/policy/operator/deployable_by_olm_test.go
+++ b/certification/internal/policy/operator/deployable_by_olm_test.go
@@ -40,6 +40,7 @@ var _ = Describe("DeployableByOLMCheck", func() {
 		annotations            = `annotations:
   operators.operatorframework.io.bundle.package.v1: testPackage
   operators.operatorframework.io.bundle.channel.default.v1: testChannel
+  operators.operatorframework.io.bundle.channels.v1: testChannel
 `
 		registryAuthToken = `{
 "auths": {
@@ -49,17 +50,18 @@ var _ = Describe("DeployableByOLMCheck", func() {
   }
 }`
 
-		csvStr = `
-    spec:
-      installModes:
-        - supported: false
-          type: OwnNamespace
-        - supported: false
-          type: SingleNamespace
-        - supported: false
-          type: MultiNamespace
-        - supported: true
-          type: AllNamespaces
+		csvStr = `apiVersion: operators.coreos.com/v1alpha1
+kind: ClusterServiceVersion
+spec:
+  installModes:
+    - supported: false
+      type: OwnNamespace
+    - supported: false
+      type: SingleNamespace
+    - supported: false
+      type: MultiNamespace
+    - supported: true
+      type: AllNamespaces
 `
 	)
 	BeforeEach(func() {