Repository: redhat-openshift-ecosystem/openshift-preflight
Pull request #406 (2022-02-11 17:14:01)

Make GetProject an exported method of PyxisEngine
Since we will need to check the os-content-type of the project
to determine which checks will be run, GetProject needs to be
exported, and called early in the execution of preflight check
container.

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/406#" 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":[]} -->
openshift-ci[bot]: @acornett21: changing LGTM is restricted to collaborators

<details>

In response to [this](https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/406#pullrequestreview-880466332):

>


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>
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/406#pullrequestreview-880466332" title="Approved">acornett21</a>*, *<a href="https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/406#" 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":[]} -->
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/406#pullrequestreview-880466332" title="Approved">acornett21</a>*, *<a href="https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/406#" title="Author self-approved">bcrochet</a>*, *<a href="https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/406#pullrequestreview-880472690" title="Approved">samira-barouti</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,samira-barouti]

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":[]} -->
openshift-ci[bot]: New changes are detected. LGTM label has been removed.
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/406#pullrequestreview-880466332" title="Approved">acornett21</a>*, *<a href="https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/406#" title="Author self-approved">bcrochet</a>*, *<a href="https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/406#pullrequestreview-880639012" title="LGTM">samira-barouti</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,samira-barouti]

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":[]} -->
openshift-ci[bot]: New changes are detected. LGTM label has been removed.

Patch:
diff --git a/certification/engine/engine.go b/certification/engine/engine.go
index 6b06003..33638f0 100644
--- a/certification/engine/engine.go
+++ b/certification/engine/engine.go
@@ -59,7 +59,9 @@ func queryChecks(checkName string) certification.Check {
 	if check, exists := operatorPolicy[checkName]; exists {
 		return check
 	}
-	// if not found in Operator Policy, query container policy
+	// if not found in Operator Policy, query container policy.
+	// No need to check scratch container policy since this is
+	// a superset.
 	if check, exists := containerPolicy[checkName]; exists {
 		return check
 	}
@@ -105,6 +107,15 @@ var containerPolicy = map[string]certification.Check{
 	runnableContainerCheck.Name(): runnableContainerCheck,
 }
 
+var scratchContainerPolicy = map[string]certification.Check{
+	hasLicenseCheck.Name():        hasLicenseCheck,
+	hasUniqueTagCheck.Name():      hasUniqueTagCheck,
+	maxLayersCheck.Name():         maxLayersCheck,
+	hasRequiredLabelsCheck.Name(): hasRequiredLabelsCheck,
+	runAsRootCheck.Name():         runAsRootCheck,
+	runnableContainerCheck.Name(): runnableContainerCheck,
+}
+
 func makeCheckList(checkMap map[string]certification.Check) []string {
 	checks := make([]string, len(checkMap))
 	i := 0
@@ -124,3 +135,7 @@ func OperatorPolicy() []string {
 func ContainerPolicy() []string {
 	return makeCheckList(containerPolicy)
 }
+
+func ScratchContainerPolicy() []string {
+	return makeCheckList(scratchContainerPolicy)
+}
diff --git a/certification/internal/cli/podman.go b/certification/internal/cli/podman.go
index e10a299..28c208d 100644
--- a/certification/internal/cli/podman.go
+++ b/certification/internal/cli/podman.go
@@ -1,7 +1,5 @@
 package cli
 
-import "time"
-
 type PodmanCreateOutput struct {
 	ContainerId string
 	Stdout      string
@@ -25,7 +23,6 @@ type ImagePullOptions struct {
 type WaitOptions struct {
 	Interval  string
 	Condition string
-	Timeout   time.Duration
 }
 
 type InspectContainerData struct {
diff --git a/certification/internal/engine/podman.go b/certification/internal/engine/podman.go
index 6e3064d..76595ed 100644
--- a/certification/internal/engine/podman.go
+++ b/certification/internal/engine/podman.go
@@ -2,7 +2,6 @@ package engine
 
 import (
 	"bytes"
-	"context"
 	"fmt"
 	"os/exec"
 	"strings"
@@ -154,10 +153,7 @@ func (p *podmanEngine) WaitContainer(containerId string, waitOptions cli.WaitOpt
 	}
 	cmdArgs = append(cmdArgs, containerId)
 
-	ctx, cancel := context.WithTimeout(context.Background(), waitOptions.Timeout)
-	defer cancel()
-
-	cmd := exec.CommandContext(ctx, "podman", cmdArgs...)
+	cmd := exec.Command("podman", cmdArgs...)
 
 	log.Debugf("Command being run: %+v", cmd)
 
@@ -168,9 +164,6 @@ func (p *podmanEngine) WaitContainer(containerId string, waitOptions cli.WaitOpt
 	if err := cmd.Run(); err != nil {
 		log.Error(fmt.Sprintf("unable to wait for container %s: ", containerId), err)
 		log.Error("Stderr: ", stderr.String())
-		if strings.Contains(strings.ToLower(err.Error()), "killed") {
-			return false, nil
-		}
 		return false, err
 	}
 
diff --git a/certification/internal/policy/container/defaults.go b/certification/internal/policy/container/defaults.go
index af3adc5..c5614e0 100644
--- a/certification/internal/policy/container/defaults.go
+++ b/certification/internal/policy/container/defaults.go
@@ -6,5 +6,4 @@ import (
 
 var (
 	checkContainerTimeout time.Duration = 10 * time.Second
-	waitContainer         time.Duration = 2 * time.Second
 )
diff --git a/certification/internal/policy/container/runnable_container.go b/certification/internal/policy/container/runnable_container.go
index 8b1faff..cf04b6c 100644
--- a/certification/internal/policy/container/runnable_container.go
+++ b/certification/internal/policy/container/runnable_container.go
@@ -42,9 +42,8 @@ func (p *RunnableContainerCheck) Validate(imgRef certification.ImageReference) (
 	}
 
 	return p.PodmanEngine.WaitContainer(creationOutput.ContainerId, cli.WaitOptions{
-		Interval:  waitContainer.String(),
+		Interval:  checkContainerTimeout.String(),
 		Condition: define.ContainerStateRunning.String(),
-		Timeout:   checkContainerTimeout,
 	})
 }
 
diff --git a/certification/pyxis/pyxis.go b/certification/pyxis/pyxis.go
index 1f52bfe..d62fba8 100644
--- a/certification/pyxis/pyxis.go
+++ b/certification/pyxis/pyxis.go
@@ -27,7 +27,7 @@ type pyxisEngine struct {
 }
 
 func getPyxisUrl(path string) string {
-	return fmt.Sprintf("https://%s/%s/%s", viper.GetString("pyxis-host"), apiVersion, path)
+	return fmt.Sprintf("https://%s/%s/%s", viper.GetString("pyxis_host"), apiVersion, path)
 }
 
 func NewPyxisEngine(apiToken string, projectId string, httpClient HTTPClient) *pyxisEngine {
diff --git a/certification/pyxis/submit.go b/certification/pyxis/submit.go
index 0f3a25f..0b0e09b 100644
--- a/certification/pyxis/submit.go
+++ b/certification/pyxis/submit.go
@@ -2,34 +2,21 @@ package pyxis
 
 import (
 	"context"
-	"strings"
 
-	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/errors"
 	log "github.com/sirupsen/logrus"
 )
 
-func (p *pyxisEngine) SubmitResults(containerImage string) (*CertProject, *CertImage, error) {
+func (p *pyxisEngine) SubmitResults(certProject *CertProject) (*CertProject, *CertImage, error) {
+	var err error
 	ctx := context.Background()
-	projectId := p.ProjectId
-	if projectId == "" {
-		return nil, nil, errors.ErrEmptyProjectID
-	}
-	if strings.HasPrefix(projectId, "ospid-") {
-		projectId = strings.Split(projectId, "-")[1]
-	}
-	project, err := p.GetProject(ctx)
-	if err != nil {
-		log.Error(err, "could not retrieve project")
-		return nil, nil, err
-	}
-	oldProject := project
+	oldProject := certProject
 
-	if project.CertificationStatus == "Started" {
-		project.CertificationStatus = "In Progress"
+	if certProject.CertificationStatus == "Started" {
+		certProject.CertificationStatus = "In Progress"
 	}
 
-	if project != oldProject {
-		project, err = p.updateProject(ctx, projectId, project)
+	if certProject != oldProject {
+		certProject, err = p.updateProject(ctx, p.ProjectId, certProject)
 		if err != nil {
 			log.Error(err, "could not update project")
 			return nil, nil, err
@@ -50,5 +37,5 @@ func (p *pyxisEngine) SubmitResults(containerImage string) (*CertProject, *CertI
 		return nil, nil, err
 	}
 
-	return project, certImage, nil
+	return certProject, certImage, nil
 }
diff --git a/certification/pyxis/types.go b/certification/pyxis/types.go
index 1a97742..bba36b6 100644
--- a/certification/pyxis/types.go
+++ b/certification/pyxis/types.go
@@ -66,6 +66,7 @@ type CertProject struct {
 	Name                string    `json:"name"`                      // required
 	ProjectStatus       string    `json:"project_status"`            // required
 	Type                string    `json:"type" default:"Containers"` // required
+	OsContentType       string    `json:"os_content_type,omitempty"`
 }
 
 type Container struct {
diff --git a/cmd/check_container.go b/cmd/check_container.go
index 07a6b9e..efb2424 100644
--- a/cmd/check_container.go
+++ b/cmd/check_container.go
@@ -1,8 +1,10 @@
 package cmd
 
 import (
+	"context"
 	"fmt"
 	"io"
+	"net/http"
 	"os"
 	"path/filepath"
 	"strings"
@@ -11,6 +13,7 @@ import (
 	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/engine"
 	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/errors"
 	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/formatters"
+	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/pyxis"
 	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/runtime"
 	"github.com/redhat-openshift-ecosystem/openshift-preflight/version"
 	log "github.com/sirupsen/logrus"
@@ -53,6 +56,26 @@ var checkContainerCmd = &cobra.Command{
 			ResponseFormat: DefaultOutputFormat,
 		}
 
+		projectId := viper.GetString("certification_project_id")
+		if projectId == "" {
+			return errors.ErrEmptyProjectID
+		}
+		if strings.HasPrefix(projectId, "ospid-") {
+			projectId = strings.Split(projectId, "-")[1]
+		}
+		apiToken := viper.GetString("pyxis_api_token")
+		ctx := context.Background()
+		pyxisEngine := pyxis.NewPyxisEngine(apiToken, projectId, &http.Client{})
+		project, err := pyxisEngine.GetProject(ctx)
+		if err != nil {
+			log.Error(err, "could not retrieve project")
+			return err
+		}
+		log.Debugf("Certification project name is: %s", project.Name)
+		if project.OsContentType == "scratch" {
+			cfg.EnabledChecks = engine.ScratchContainerPolicy()
+		}
+
 		engine, err := engine.NewForConfig(cfg)
 		if err != nil {
 			return err
@@ -106,6 +129,10 @@ var checkContainerCmd = &cobra.Command{
 func init() {
 	checkContainerCmd.Flags().String("pyxis-api-token", "", "API token for Pyxis authentication")
 	viper.BindPFlag("pyxis_api_token", checkContainerCmd.Flags().Lookup("pyxis-api-token"))
+	checkContainerCmd.Flags().String("pyxis-host", DefaultPyxisHost, "Host to use for Pyxis submissions.")
+	viper.BindPFlag("pyxis_host", checkContainerCmd.Flags().Lookup("pyxis-host"))
+	checkContainerCmd.Flags().String("certification-project-id", "", "Certification Project ID from conenct.redhat.com. Should be supplied without the ospid- prefix.")
+	viper.BindPFlag("certification_project_id", checkContainerCmd.Flags().Lookup("certification-project-id"))
 
 	checkCmd.AddCommand(checkContainerCmd)
 }


Test patch:
diff --git a/certification/internal/policy/container/container_suite_test.go b/certification/internal/policy/container/container_suite_test.go
index 1ff737f..d8be77b 100644
--- a/certification/internal/policy/container/container_suite_test.go
+++ b/certification/internal/policy/container/container_suite_test.go
@@ -1,7 +1,6 @@
 package container
 
 import (
-	"errors"
 	"io"
 	"testing"
 
@@ -9,7 +8,6 @@ import (
 	"github.com/google/go-containerregistry/pkg/v1/types"
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
-	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/internal/cli"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -48,51 +46,3 @@ func (fl FakeLayer) Size() (int64, error) {
 func (fl FakeLayer) MediaType() (types.MediaType, error) {
 	return "mediatype", nil
 }
-
-type GoodPodmanEngine struct{}
-
-func (pe GoodPodmanEngine) PullImage(imageURI string, options cli.ImagePullOptions) (*cli.PodmanOutput, error) {
-	return &cli.PodmanOutput{}, nil
-}
-
-func (pe GoodPodmanEngine) CreateContainer(imageURI string, createOptions cli.PodmanCreateOption) (*cli.PodmanCreateOutput, error) {
-	return &cli.PodmanCreateOutput{
-		ContainerId: "containerId",
-	}, nil
-}
-
-func (p GoodPodmanEngine) StartContainer(nameOrId string) (*cli.PodmanOutput, error) {
-	return &cli.PodmanOutput{}, nil
-}
-
-func (p GoodPodmanEngine) RemoveContainer(containerId string) error {
-	return nil
-}
-
-func (p GoodPodmanEngine) WaitContainer(containerId string, waitOptions cli.WaitOptions) (bool, error) {
-	return true, nil
-}
-
-type BadPodmanEngine struct{}
-
-func (pe BadPodmanEngine) PullImage(imageURI string, options cli.ImagePullOptions) (*cli.PodmanOutput, error) {
-	return &cli.PodmanOutput{}, nil
-}
-
-func (pe BadPodmanEngine) CreateContainer(imageURI string, createOptions cli.PodmanCreateOption) (*cli.PodmanCreateOutput, error) {
-	return &cli.PodmanCreateOutput{
-		ContainerId: "containerId",
-	}, nil
-}
-
-func (p BadPodmanEngine) StartContainer(nameOrId string) (*cli.PodmanOutput, error) {
-	return &cli.PodmanOutput{}, nil
-}
-
-func (p BadPodmanEngine) RemoveContainer(containerId string) error {
-	return nil
-}
-
-func (p BadPodmanEngine) WaitContainer(containerId string, waitOptions cli.WaitOptions) (bool, error) {
-	return false, errors.New("the container wait had failed")
-}
diff --git a/certification/internal/policy/container/runnable_container_test.go b/certification/internal/policy/container/runnable_container_test.go
deleted file mode 100644
index 2e9f78f..0000000
--- a/certification/internal/policy/container/runnable_container_test.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package container
-
-import (
-	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification/internal/cli"
-
-	. "github.com/onsi/ginkgo"
-	. "github.com/onsi/gomega"
-	"github.com/redhat-openshift-ecosystem/openshift-preflight/certification"
-)
-
-var _ = Describe("RunnableContainerCheck", func() {
-	var (
-		engine                 cli.PodmanEngine
-		runnableContainerCheck RunnableContainerCheck
-		imageRef               certification.ImageReference
-	)
-
-	BeforeEach(func() {
-		imageRef.ImageURI = "test-image:test-tag"
-	})
-
-	Describe("Checking that the container runs within a specified timeframe", func() {
-		Context("When container starts successfully", func() {
-			It("should pass Validate", func() {
-				engine = GoodPodmanEngine{}
-				runnableContainerCheck = *NewRunnableContainerCheck(&engine)
-				ok, err := runnableContainerCheck.Validate(imageRef)
-				Expect(err).ToNot(HaveOccurred())
-				Expect(ok).To(BeTrue())
-			})
-		})
-		Context("When container does not run successfully", func() {
-			It("should not pass Validate", func() {
-				engine = BadPodmanEngine{}
-				runnableContainerCheck = *NewRunnableContainerCheck(&engine)
-				ok, err := runnableContainerCheck.Validate(imageRef)
-				Expect(err).To(HaveOccurred())
-				Expect(ok).To(BeFalse())
-			})
-		})
-	})
-
-})
diff --git a/certification/pyxis/submit_test.go b/certification/pyxis/submit_test.go
index 8f87024..6affa81 100644
--- a/certification/pyxis/submit_test.go
+++ b/certification/pyxis/submit_test.go
@@ -16,7 +16,7 @@ var _ = Describe("Pyxis Submit", func() {
 	Context("when a project is submitted", func() {
 		Context("and it is not already In Progress", func() {
 			It("should switch to In Progress", func() {
-				certProject, certImage, err := pyxisEngine.SubmitResults("foo/container")
+				certProject, certImage, err := pyxisEngine.SubmitResults(&CertProject{})
 				Expect(err).ToNot(HaveOccurred())
 				Expect(certProject).ToNot(BeNil())
 				Expect(certImage).ToNot(BeNil())