mirror of
https://github.com/project-zot/zot.git
synced 2024-12-30 22:34:13 -05:00
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 <andaaron@cisco.com>
This commit is contained in:
parent
ac6c6a844c
commit
1d9c88c313
4 changed files with 111 additions and 71 deletions
|
@ -4,19 +4,14 @@
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/briandowns/spinner"
|
"github.com/briandowns/spinner"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"gopkg.in/resty.v1"
|
|
||||||
|
|
||||||
zotErrors "zotregistry.io/zot/errors"
|
zotErrors "zotregistry.io/zot/errors"
|
||||||
"zotregistry.io/zot/pkg/api/constants"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCveCommand(searchService SearchService) *cobra.Command {
|
func NewCveCommand(searchService SearchService) *cobra.Command {
|
||||||
|
@ -142,74 +137,10 @@ type cveFlagVariables struct {
|
||||||
debug *bool
|
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 {
|
func searchCve(searchConfig searchConfig) error {
|
||||||
var searchers []searcher
|
var searchers []searcher
|
||||||
|
|
||||||
if checkExtEndPoint(*searchConfig.servURL) {
|
if checkExtEndPoint(searchConfig) {
|
||||||
searchers = getCveSearchersGQL()
|
searchers = getCveSearchersGQL()
|
||||||
} else {
|
} else {
|
||||||
searchers = getCveSearchers()
|
searchers = getCveSearchers()
|
||||||
|
|
100
pkg/cli/discover.go
Normal file
100
pkg/cli/discover.go
Normal file
|
@ -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")
|
||||||
|
}
|
|
@ -138,7 +138,7 @@ func setupImageFlags(imageCmd *cobra.Command, searchImageParams map[string]*stri
|
||||||
func searchImage(searchConfig searchConfig) error {
|
func searchImage(searchConfig searchConfig) error {
|
||||||
var searchers []searcher
|
var searchers []searcher
|
||||||
|
|
||||||
if checkExtEndPoint(*searchConfig.servURL) {
|
if checkExtEndPoint(searchConfig) {
|
||||||
searchers = getImageSearchersGQL()
|
searchers = getImageSearchersGQL()
|
||||||
} else {
|
} else {
|
||||||
searchers = getImageSearchers()
|
searchers = getImageSearchers()
|
||||||
|
|
|
@ -324,6 +324,15 @@ func getImage(ctx context.Context, config searchConfig, username, password, imag
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tag := range tagList.Tags {
|
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)
|
wtgrp.Add(1)
|
||||||
|
|
||||||
go addManifestCallToPool(ctx, config, pool, username, password, imageName, tag, rch, wtgrp)
|
go addManifestCallToPool(ctx, config, pool, username, password, imageName, tag, rch, wtgrp)
|
||||||
|
|
Loading…
Reference in a new issue