mirror of
https://github.com/project-zot/zot.git
synced 2026-06-15 11:37:56 +08:00
2402296e9a
* fix: migrate to Go module v2 for proper semantic versioning This change updates the module path from 'zotregistry.dev/zot' to 'zotregistry.dev/zot/v2' to comply with Go's semantic versioning rules. According to Go's module versioning requirements, major version v2+ must include the major version in the module path. The current module path 'zotregistry.dev/zot' only supports v0.x.x and v1.x.x versions, making existing v2.x.x tags (like v2.1.8) unusable. Changes: - Updated go.mod module path to zotregistry.dev/zot/v2 - Updated all internal import paths across 280+ Go source files - Updated configuration files (golangcilint.yaml, gqlgen.yml) - Updated README.md Go reference badge This fix enables proper use of existing v2.x.x Git tags and allows external packages to import zot v2+ versions without compatibility errors. Resolves: Go module import compatibility for v2+ versions Fixes: #3071 Signed-off-by: Luca Muscariello <muscariello@ieee.org> * fix: regenerate GraphQL files with updated v2 import paths The gqlgen tool needs to regenerate the GraphQL schema files after the module path change to use the new v2 imports. Signed-off-by: Luca Muscariello <muscariello@ieee.org> --------- Signed-off-by: Luca Muscariello <muscariello@ieee.org>
169 lines
3.9 KiB
Go
169 lines
3.9 KiB
Go
//go:build search
|
|
// +build search
|
|
|
|
package client
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
|
|
|
|
zerr "zotregistry.dev/zot/v2/errors"
|
|
"zotregistry.dev/zot/v2/pkg/api/constants"
|
|
zcommon "zotregistry.dev/zot/v2/pkg/common"
|
|
)
|
|
|
|
type field struct {
|
|
Name string `json:"name"`
|
|
Args []struct {
|
|
Name string `json:"name"`
|
|
} `json:"args"`
|
|
}
|
|
|
|
type schemaList struct {
|
|
Data struct {
|
|
Schema struct {
|
|
QueryType struct {
|
|
Fields []field `json:"fields"`
|
|
} `json:"queryType"` //nolint:tagliatelle // graphQL schema
|
|
Types []typeInfo `json:"types"`
|
|
} `json:"__schema"` //nolint:tagliatelle // graphQL schema
|
|
} `json:"data"`
|
|
Errors []zcommon.ErrorGQL `json:"errors"`
|
|
}
|
|
|
|
type typeInfo struct {
|
|
Name string `json:"name"`
|
|
Fields []typeField `json:"fields"`
|
|
}
|
|
|
|
type typeField struct {
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
func containsGQLQueryWithParams(queryList []field, serverGQLTypesList []typeInfo, requiredQueries ...GQLQuery) error {
|
|
serverGQLTypes := map[string][]typeField{}
|
|
|
|
for _, typeInfo := range serverGQLTypesList {
|
|
serverGQLTypes[typeInfo.Name] = typeInfo.Fields
|
|
}
|
|
|
|
for _, reqQuery := range requiredQueries {
|
|
foundQuery := false
|
|
|
|
for _, query := range queryList {
|
|
if query.Name == reqQuery.Name && haveSameArgs(query, reqQuery) {
|
|
foundQuery = true
|
|
}
|
|
}
|
|
|
|
if !foundQuery {
|
|
return fmt.Errorf("%w: %s", zerr.ErrGQLQueryNotSupported, reqQuery.Name)
|
|
}
|
|
|
|
// let's check just the name of the returned type
|
|
returnType := reqQuery.ReturnType.Name
|
|
|
|
// we can next define fields of the returned types and check them recursively
|
|
// for now we will just check the name of the returned type to be known by the server
|
|
_, ok := serverGQLTypes[returnType]
|
|
if !ok {
|
|
return fmt.Errorf("%w: server doesn't support needed type '%s'", zerr.ErrGQLQueryNotSupported, returnType)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func haveSameArgs(query field, reqQuery GQLQuery) bool {
|
|
if len(query.Args) != len(reqQuery.Args) {
|
|
return false
|
|
}
|
|
|
|
for i := range query.Args {
|
|
if query.Args[i].Name != reqQuery.Args[i] {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func CheckExtEndPointQuery(config SearchConfig, requiredQueries ...GQLQuery) error {
|
|
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 err
|
|
}
|
|
|
|
discoverResponse := &distext.ExtensionList{}
|
|
|
|
_, err = makeGETRequest(ctx, discoverEndPoint, username, password, config.VerifyTLS,
|
|
config.Debug, &discoverResponse, config.ResultWriter)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
searchEnabled := false
|
|
|
|
for _, extension := range discoverResponse.Extensions {
|
|
if extension.Name == constants.BaseExtension {
|
|
for _, endpoint := range extension.Endpoints {
|
|
if endpoint == constants.FullSearchPrefix {
|
|
searchEnabled = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if !searchEnabled {
|
|
return fmt.Errorf("%w: search extension gql endpoints not found", zerr.ErrExtensionNotEnabled)
|
|
}
|
|
|
|
searchEndPoint, _ := combineServerAndEndpointURL(config.ServURL, constants.FullSearchPrefix)
|
|
|
|
schemaQuery := `
|
|
{
|
|
__schema {
|
|
queryType {
|
|
fields {
|
|
name
|
|
args {
|
|
name
|
|
}
|
|
type {
|
|
name
|
|
kind
|
|
}
|
|
}
|
|
__typename
|
|
}
|
|
types {
|
|
name
|
|
fields {
|
|
name
|
|
}
|
|
}
|
|
}
|
|
}`
|
|
|
|
queryResponse := &schemaList{}
|
|
|
|
err = makeGraphQLRequest(ctx, searchEndPoint, schemaQuery, username, password, config.VerifyTLS,
|
|
config.Debug, queryResponse, config.ResultWriter)
|
|
if err != nil {
|
|
return fmt.Errorf("gql query failed: %w", err)
|
|
}
|
|
|
|
if err = checkResultGraphQLQuery(ctx, err, queryResponse.Errors); err != nil {
|
|
return fmt.Errorf("gql query failed: %w", err)
|
|
}
|
|
|
|
return containsGQLQueryWithParams(queryResponse.Data.Schema.QueryType.Fields,
|
|
queryResponse.Data.Schema.Types, requiredQueries...)
|
|
}
|