diff --git a/certification/config.go b/certification/config.go index 91ca932e4..f11b34c4d 100644 --- a/certification/config.go +++ b/certification/config.go @@ -29,6 +29,7 @@ type containerConfig interface { PyxisHost() string PyxisAPIToken() string Submit() bool + Insecure() bool } // operatorConfig are configurables relevant to diff --git a/certification/internal/engine/engine.go b/certification/internal/engine/engine.go index 20ad39af7..54ee58b0f 100644 --- a/certification/internal/engine/engine.go +++ b/certification/internal/engine/engine.go @@ -86,6 +86,10 @@ func (c *CraneEngine) ExecuteChecks(ctx context.Context) error { retryOnceAfter(5 * time.Second), } + if c.Config.Insecure() { + options = append(options, crane.Insecure) + } + // pull the image and save to fs log.Debug("pulling image from target registry") img, err := crane.Pull(c.Image, options...) diff --git a/certification/internal/policy/container/has_unique_tag.go b/certification/internal/policy/container/has_unique_tag.go index 5f9475ff1..192883745 100644 --- a/certification/internal/policy/container/has_unique_tag.go +++ b/certification/internal/policy/container/has_unique_tag.go @@ -3,14 +3,12 @@ package container import ( "context" "fmt" - goruntime "runtime" "strings" "github.com/redhat-openshift-ecosystem/openshift-preflight/certification" "github.com/redhat-openshift-ecosystem/openshift-preflight/certification/internal/authn" "github.com/google/go-containerregistry/pkg/crane" - cranev1 "github.com/google/go-containerregistry/pkg/v1" ) var _ certification.Check = &hasUniqueTagCheck{} @@ -59,10 +57,6 @@ func (p *hasUniqueTagCheck) getDataToValidate(ctx context.Context, image string) options := []crane.Option{ crane.WithContext(ctx), crane.WithAuthFromKeychain(authn.PreflightKeychain(authn.WithDockerConfig(p.dockercfg))), - crane.WithPlatform(&cranev1.Platform{ - OS: "linux", - Architecture: goruntime.GOARCH, - }), } return crane.ListTags(image, options...) diff --git a/certification/runtime/config.go b/certification/runtime/config.go index 9dc7f18f2..95939ae19 100644 --- a/certification/runtime/config.go +++ b/certification/runtime/config.go @@ -24,6 +24,7 @@ type Config struct { PyxisAPIToken string DockerConfig string Submit bool + Insecure bool // Operator-Specific Fields Namespace string ServiceAccount string @@ -63,6 +64,7 @@ func (c *Config) storeContainerPolicyConfiguration(vcfg viper.Viper) { c.Submit = vcfg.GetBool("submit") c.PyxisHost = pyxisHostLookup(vcfg.GetString("pyxis_env"), vcfg.GetString("pyxis_host")) c.CertificationProjectID = vcfg.GetString("certification_project_id") + c.Insecure = vcfg.GetBool("insecure") } // storeOperatorPolicyConfiguration reads operator-policy-specific config diff --git a/certification/runtime/config_read.go b/certification/runtime/config_read.go index 0187e30b7..4d92908ca 100644 --- a/certification/runtime/config_read.go +++ b/certification/runtime/config_read.go @@ -93,3 +93,7 @@ func (ro *ReadOnlyConfig) Kubeconfig() string { func (ro *ReadOnlyConfig) IndexImage() string { return ro.cfg.IndexImage } + +func (ro *ReadOnlyConfig) Insecure() bool { + return ro.cfg.Insecure +} diff --git a/certification/runtime/config_read_test.go b/certification/runtime/config_read_test.go index f61540086..6aa40942d 100644 --- a/certification/runtime/config_read_test.go +++ b/certification/runtime/config_read_test.go @@ -21,6 +21,7 @@ var _ = Describe("Runtime ReadOnlyConfig test", func() { PyxisAPIToken: "pyxisapitoken", DockerConfig: "dockercfg", Submit: true, + Insecure: true, Namespace: "ns", ServiceAccount: "sa", ScorecardImage: "scorecardimg", @@ -44,6 +45,7 @@ var _ = Describe("Runtime ReadOnlyConfig test", func() { Expect(cro.PyxisAPIToken()).To(Equal("pyxisapitoken")) Expect(cro.DockerConfig()).To(Equal("dockercfg")) Expect(cro.Submit()).To(Equal(true)) + Expect(cro.Insecure()).To(BeTrue()) Expect(cro.Namespace()).To(Equal("ns")) Expect(cro.ServiceAccount()).To(Equal("sa")) Expect(cro.ScorecardImage()).To(Equal("scorecardimg")) diff --git a/certification/runtime/config_test.go b/certification/runtime/config_test.go index b07f6317c..2a064abc2 100644 --- a/certification/runtime/config_test.go +++ b/certification/runtime/config_test.go @@ -37,6 +37,8 @@ var _ = Describe("Viper to Runtime Config", func() { expectedRuntimeCfg.PyxisHost = "catalog.redhat.com/api/containers" baseViperCfg.Set("certification_project_id", "000000000000") expectedRuntimeCfg.CertificationProjectID = "000000000000" + baseViperCfg.Set("insecure", true) + expectedRuntimeCfg.Insecure = true baseViperCfg.Set("namespace", "myns") expectedRuntimeCfg.Namespace = "myns" @@ -66,6 +68,6 @@ var _ = Describe("Viper to Runtime Config", func() { // accurate in confirming that the derived configuration from viper // matches. keys := reflect.TypeOf(Config{}).NumField() - Expect(keys).To(Equal(20)) + Expect(keys).To(Equal(21)) }) }) diff --git a/cmd/preflight/cmd/check_container.go b/cmd/preflight/cmd/check_container.go index 9911a74ba..d1d46f74e 100644 --- a/cmd/preflight/cmd/check_container.go +++ b/cmd/preflight/cmd/check_container.go @@ -30,22 +30,30 @@ func checkContainerCmd() *cobra.Command { RunE: checkContainerRunE, } - checkContainerCmd.Flags().BoolVarP(&submit, "submit", "s", false, "submit check container results to red hat") - _ = viper.BindPFlag("submit", checkContainerCmd.Flags().Lookup("submit")) + flags := checkContainerCmd.Flags() - checkContainerCmd.Flags().String("pyxis-api-token", "", "API token for Pyxis authentication (env: PFLT_PYXIS_API_TOKEN)") - _ = viper.BindPFlag("pyxis_api_token", checkContainerCmd.Flags().Lookup("pyxis-api-token")) + flags.BoolVarP(&submit, "submit", "s", false, "submit check container results to Red Hat") + _ = viper.BindPFlag("submit", flags.Lookup("submit")) - checkContainerCmd.Flags().String("pyxis-host", "", fmt.Sprintf("Host to use for Pyxis submissions. This will override Pyxis Env. Only set this if you know what you are doing.\n"+ + flags.Bool("insecure", false, "Use insecure protocol for the registry. Default is False. Cannot be used with submit.") + _ = viper.BindPFlag("insecure", flags.Lookup("insecure")) + + // Make --submit mutually exclusive to --insecure + checkContainerCmd.MarkFlagsMutuallyExclusive("submit", "insecure") + + flags.String("pyxis-api-token", "", "API token for Pyxis authentication (env: PFLT_PYXIS_API_TOKEN)") + _ = viper.BindPFlag("pyxis_api_token", flags.Lookup("pyxis-api-token")) + + flags.String("pyxis-host", "", fmt.Sprintf("Host to use for Pyxis submissions. This will override Pyxis Env. Only set this if you know what you are doing.\n"+ "If you do set it, it should include just the host, and the URI path. (env: PFLT_PYXIS_HOST)")) - _ = viper.BindPFlag("pyxis_host", checkContainerCmd.Flags().Lookup("pyxis-host")) + _ = viper.BindPFlag("pyxis_host", flags.Lookup("pyxis-host")) - checkContainerCmd.Flags().String("pyxis-env", certification.DefaultPyxisEnv, "Env to use for Pyxis submissions.") - _ = viper.BindPFlag("pyxis_env", checkContainerCmd.Flags().Lookup("pyxis-env")) + flags.String("pyxis-env", certification.DefaultPyxisEnv, "Env to use for Pyxis submissions.") + _ = viper.BindPFlag("pyxis_env", flags.Lookup("pyxis-env")) - checkContainerCmd.Flags().String("certification-project-id", "", fmt.Sprintf("Certification Project ID from connect.redhat.com/projects/{certification-project-id}/overview\n"+ + flags.String("certification-project-id", "", fmt.Sprintf("Certification Project ID from connect.redhat.com/projects/{certification-project-id}/overview\n"+ "URL paramater. This value may differ from the PID on the overview page. (env: PFLT_CERTIFICATION_PROJECT_ID)")) - _ = viper.BindPFlag("certification_project_id", checkContainerCmd.Flags().Lookup("certification-project-id")) + _ = viper.BindPFlag("certification_project_id", flags.Lookup("certification-project-id")) return checkContainerCmd } diff --git a/cmd/preflight/cmd/check_container_test.go b/cmd/preflight/cmd/check_container_test.go index 2656ab1aa..a8082c5cc 100644 --- a/cmd/preflight/cmd/check_container_test.go +++ b/cmd/preflight/cmd/check_container_test.go @@ -55,6 +55,7 @@ var _ = Describe("Check Container Command", func() { Entry("certification-project-id flag is present but empty because of '='", "cannot be empty when --submit is present", []string{"foo", "--submit", "--certification-project-id=", "--pyxis-api-token=footoken"}), Entry("submit is passed after empty api token", "pyxis API token and certification ID are required when --submit is present", []string{"foo", "--certification-project-id=fooid", "--pyxis-api-token", "--submit"}), Entry("submit is passed with explicit value after empty api token", "pyxis API token and certification ID are required when --submit is present", []string{"foo", "--certification-project-id=fooid", "--pyxis-api-token", "--submit=true"}), + Entry("submit is passed and insecure is specified", "if any flags in the group [submit insecure] are set", []string{"foo", "--submit", "--insecure", "--certification-project-id=fooid", "--pyxis-api-token=footoken"}), ) When("the user enables the submit flag", func() { diff --git a/docs/RECIPES.md b/docs/RECIPES.md index 272345fc0..c87e4c4cb 100644 --- a/docs/RECIPES.md +++ b/docs/RECIPES.md @@ -229,3 +229,19 @@ $CONTAINER_TOOL run \ -v ./temp-authfile.json:/temp-authfile.json:ro \ quay.io/opdev/preflight:stable check container registry.example.org/your-namespace/your-bundle-image:sometag --submit ``` + +### Testing a local container, i.e. not yet pushed to a registry + +Preflight does not support certifying against a local image, that is not pushed to +a registry. In some cases, like a CI system, it is desirable to run preflight against +an image BEFORE pushing to a public registry. In order to support that, one should +start a local registry, push to it, and point preflight at the local registry. + +```bash +podman run -p 5000:5000 docker.io/library/registry +podman push --tls-verify=false localhost/myrepo/mycontainer:v1.0 localhost:5000/myrepo/mycontainer:v1.0 +preflight check container --insecure localhost:5000/myrepo/mycontainer:v1.0 +``` + +Note: --submit and --insecure are mutually exclusive. A container cannot be fully +certified and submitted unless it is on a secure registry.