From 1d9c88c313008650ae7f15920c05770792d2e2a9 Mon Sep 17 00:00:00 2001 From: Andrei Aaron Date: Sun, 23 Oct 2022 09:44:20 +0300 Subject: [PATCH] fix(cli): do not show signatures and fix tls verification client side (#904) Issues fixed: - the cli calls reaching out to the catalog endpoint used to request signature manifests - resty was used instead of the cli http client to check if the discovery api was available but it did not take into account TLS verification configuration (testing locally withself-signed certificates did not work) (cherry picked from commit ca42031ae9b1ceb459f5cd4f86cb82b3c9f78157) Signed-off-by: Andrei Aaron --- pkg/cli/cve_cmd.go | 71 +----------------------------- pkg/cli/discover.go | 100 +++++++++++++++++++++++++++++++++++++++++++ pkg/cli/image_cmd.go | 2 +- pkg/cli/service.go | 9 ++++ 4 files changed, 111 insertions(+), 71 deletions(-) create mode 100644 pkg/cli/discover.go diff --git a/pkg/cli/cve_cmd.go b/pkg/cli/cve_cmd.go index 4b74c476..c103d67d 100644 --- a/pkg/cli/cve_cmd.go +++ b/pkg/cli/cve_cmd.go @@ -4,19 +4,14 @@ package cli import ( - "encoding/json" "fmt" - "net/http" - "net/url" "os" "path" "github.com/briandowns/spinner" "github.com/spf13/cobra" - "gopkg.in/resty.v1" zotErrors "zotregistry.io/zot/errors" - "zotregistry.io/zot/pkg/api/constants" ) func NewCveCommand(searchService SearchService) *cobra.Command { @@ -142,74 +137,10 @@ type cveFlagVariables struct { debug *bool } -type field struct { - Name string `json:"name"` -} - -type schemaList struct { - Data struct { - Schema struct { - QueryType struct { - Fields []field `json:"fields"` - } `json:"queryType"` //nolint:tagliatelle // graphQL schema - } `json:"__schema"` //nolint:tagliatelle // graphQL schema - } `json:"data"` -} - -func containsGQLQuery(queryList []field, query string) bool { - for _, q := range queryList { - if q.Name == query { - return true - } - } - - return false -} - -func checkExtEndPoint(serverURL string) bool { - client := resty.New() - - extEndPoint, err := combineServerAndEndpointURL(serverURL, fmt.Sprintf("%s%s", - constants.RoutePrefix, constants.ExtOciDiscoverPrefix)) - if err != nil { - return false - } - - //nolint: gosec - resp, err := client.R().Get(extEndPoint) - if err != nil || resp.StatusCode() != http.StatusOK { - return false - } - - searchEndPoint, _ := combineServerAndEndpointURL(serverURL, constants.FullSearchPrefix) - - query := ` - { - __schema() { - queryType { - fields { - name - } - } - } - }` - - resp, err = client.R().Get(searchEndPoint + "?query=" + url.QueryEscape(query)) - if err != nil || resp.StatusCode() != http.StatusOK { - return false - } - - queryList := &schemaList{} - - _ = json.Unmarshal(resp.Body(), queryList) - - return containsGQLQuery(queryList.Data.Schema.QueryType.Fields, "ImageList") -} - func searchCve(searchConfig searchConfig) error { var searchers []searcher - if checkExtEndPoint(*searchConfig.servURL) { + if checkExtEndPoint(searchConfig) { searchers = getCveSearchersGQL() } else { searchers = getCveSearchers() diff --git a/pkg/cli/discover.go b/pkg/cli/discover.go new file mode 100644 index 00000000..0ac6d3fa --- /dev/null +++ b/pkg/cli/discover.go @@ -0,0 +1,100 @@ +//go:build search +// +build search + +package cli + +import ( + "context" + "fmt" + + distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions" + + "zotregistry.io/zot/pkg/api/constants" +) + +type field struct { + Name string `json:"name"` +} + +type schemaList struct { + Data struct { + Schema struct { + QueryType struct { + Fields []field `json:"fields"` + } `json:"queryType"` //nolint:tagliatelle // graphQL schema + } `json:"__schema"` //nolint:tagliatelle // graphQL schema + } `json:"data"` + Errors []errorGraphQL `json:"errors"` +} + +func containsGQLQuery(queryList []field, query string) bool { + for _, q := range queryList { + if q.Name == query { + return true + } + } + + return false +} + +func checkExtEndPoint(config searchConfig) bool { + username, password := getUsernameAndPassword(*config.user) + ctx := context.Background() + + discoverEndPoint, err := combineServerAndEndpointURL(*config.servURL, fmt.Sprintf("%s%s", + constants.RoutePrefix, constants.ExtOciDiscoverPrefix)) + if err != nil { + return false + } + + discoverResponse := &distext.ExtensionList{} + + _, err = makeGETRequest(ctx, discoverEndPoint, username, password, *config.verifyTLS, + *config.debug, &discoverResponse, config.resultWriter) + if err != nil { + return false + } + + searchEnabled := false + + for _, extension := range discoverResponse.Extensions { + if extension.Name == "_zot" { + for _, endpoint := range extension.Endpoints { + if endpoint == constants.FullSearchPrefix { + searchEnabled = true + } + } + } + } + + if !searchEnabled { + return false + } + + searchEndPoint, _ := combineServerAndEndpointURL(*config.servURL, constants.FullSearchPrefix) + + query := ` + { + __schema() { + queryType { + fields { + name + } + } + } + }` + + queryResponse := &schemaList{} + + err = makeGraphQLRequest(ctx, searchEndPoint, query, username, password, *config.verifyTLS, + *config.debug, queryResponse, config.resultWriter) + if err != nil { + return false + } + + if err = checkResultGraphQLQuery(ctx, err, queryResponse.Errors); err != nil { + return false + } + + return containsGQLQuery(queryResponse.Data.Schema.QueryType.Fields, "ImageList") +} diff --git a/pkg/cli/image_cmd.go b/pkg/cli/image_cmd.go index 0afdcfcf..ace48e02 100644 --- a/pkg/cli/image_cmd.go +++ b/pkg/cli/image_cmd.go @@ -138,7 +138,7 @@ func setupImageFlags(imageCmd *cobra.Command, searchImageParams map[string]*stri func searchImage(searchConfig searchConfig) error { var searchers []searcher - if checkExtEndPoint(*searchConfig.servURL) { + if checkExtEndPoint(searchConfig) { searchers = getImageSearchersGQL() } else { searchers = getImageSearchers() diff --git a/pkg/cli/service.go b/pkg/cli/service.go index fbb42c4f..f79d3bf8 100644 --- a/pkg/cli/service.go +++ b/pkg/cli/service.go @@ -324,6 +324,15 @@ func getImage(ctx context.Context, config searchConfig, username, password, imag } for _, tag := range tagList.Tags { + hasTagPrefix := strings.HasPrefix(tag, "sha256-") + hasTagSuffix := strings.HasSuffix(tag, ".sig") + + // check if it's an image or a signature + // we don't want to show signatures in cli responses + if hasTagPrefix && hasTagSuffix { + continue + } + wtgrp.Add(1) go addManifestCallToPool(ctx, config, pool, username, password, imageName, tag, rch, wtgrp)