0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-16 21:56:37 -05:00
zot/pkg/extensions/extension_search.go

117 lines
3.6 KiB
Go
Raw Normal View History

//go:build search
// +build search
package extensions
import (
"time"
gqlHandler "github.com/99designs/gqlgen/graphql/handler"
"github.com/gorilla/mux"
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
"zotregistry.io/zot/pkg/api/config"
"zotregistry.io/zot/pkg/api/constants"
"zotregistry.io/zot/pkg/extensions/search"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
Update to graphql 1.17.13 We encountered some problems with using the existing folder structure, but it looks like running the tooling with the latest versions works after we regenerated the project using 'gql init' and refactoring to separate the login previously in resolvers.go. - the autogenerated code is now under the gql_generated folder - the file resolvers.go now contains only the code which is not rewritten by the gqlgen framework - the file schema.resolvers.go is rewritten when gqlgen runs, and we'll only keep there the actual resolvers matching query names Changes we observed to schema.resolvers.go when gqlgen runs include reordering methods, and renaming function parameters to match the names used in schema.graphql - we now have a gqlgen.yaml config file which governs the behavior of gqlgen (can be tweaked to restructure the folder structure of the generated code in the future) Looks like the new graphql server has better validation 1 Returns 422 instead of 200 for missing query string - had to update tests 2 Correctly uncovered an error in a test for a bad `%` in query string. As as result of 2, a `masked` bug was found in the way we check if images are signed with Notary, the signatures were reasched for with the media type of the image manifest itself instead of the media type for notation. Fixed this bug, and improved error messages. This bug would have also been reproducible with main branch if the bad `%` in the test would have fixed. Updated the linter to ignore some issues with the code which is always rewritten when running: `go run github.com/99designs/gqlgen@v0.17.13 generate` Add a workflow to test gqlgen works and has no uncommitted changes Signed-off-by: Andrei Aaron <andaaron@cisco.com>
2022-07-15 06:10:51 -05:00
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/storage"
)
// We need this object to be a singleton as read/writes in the CVE DB may
// occur at any time via DB downloads as well as during scanning.
// The library doesn't seem to handle concurrency very well internally.
var cveInfo cveinfo.CveInfo //nolint:gochecknoglobals
func EnableSearchExtension(config *config.Config, log log.Logger, storeController storage.StoreController) {
if config.Extensions.Search != nil && *config.Extensions.Search.Enable && config.Extensions.Search.CVE != nil {
defaultUpdateInterval, _ := time.ParseDuration("2h")
if config.Extensions.Search.CVE.UpdateInterval < defaultUpdateInterval {
config.Extensions.Search.CVE.UpdateInterval = defaultUpdateInterval
log.Warn().Msg("CVE update interval set to too-short interval < 2h, changing update duration to 2 hours and continuing.") //nolint:lll // gofumpt conflicts with lll
}
cveInfo = cveinfo.NewCVEInfo(storeController, log)
go func() {
err := downloadTrivyDB(log, config.Extensions.Search.CVE.UpdateInterval)
if err != nil {
log.Error().Err(err).Msg("error while downloading TrivyDB")
}
}()
} else {
log.Info().Msg("CVE config not provided, skipping CVE update")
}
}
func downloadTrivyDB(log log.Logger, updateInterval time.Duration) error {
for {
log.Info().Msg("updating the CVE database")
err := cveInfo.UpdateDB()
if err != nil {
return err
}
log.Info().Str("DB update completed, next update scheduled after", updateInterval.String()).Msg("")
time.Sleep(updateInterval)
}
}
func SetupSearchRoutes(config *config.Config, router *mux.Router, storeController storage.StoreController,
log log.Logger,
) {
log.Info().Msg("setting up search routes")
if config.Extensions.Search != nil && *config.Extensions.Search.Enable {
Update to graphql 1.17.13 We encountered some problems with using the existing folder structure, but it looks like running the tooling with the latest versions works after we regenerated the project using 'gql init' and refactoring to separate the login previously in resolvers.go. - the autogenerated code is now under the gql_generated folder - the file resolvers.go now contains only the code which is not rewritten by the gqlgen framework - the file schema.resolvers.go is rewritten when gqlgen runs, and we'll only keep there the actual resolvers matching query names Changes we observed to schema.resolvers.go when gqlgen runs include reordering methods, and renaming function parameters to match the names used in schema.graphql - we now have a gqlgen.yaml config file which governs the behavior of gqlgen (can be tweaked to restructure the folder structure of the generated code in the future) Looks like the new graphql server has better validation 1 Returns 422 instead of 200 for missing query string - had to update tests 2 Correctly uncovered an error in a test for a bad `%` in query string. As as result of 2, a `masked` bug was found in the way we check if images are signed with Notary, the signatures were reasched for with the media type of the image manifest itself instead of the media type for notation. Fixed this bug, and improved error messages. This bug would have also been reproducible with main branch if the bad `%` in the test would have fixed. Updated the linter to ignore some issues with the code which is always rewritten when running: `go run github.com/99designs/gqlgen@v0.17.13 generate` Add a workflow to test gqlgen works and has no uncommitted changes Signed-off-by: Andrei Aaron <andaaron@cisco.com>
2022-07-15 06:10:51 -05:00
var resConfig gql_generated.Config
if config.Extensions.Search.CVE != nil {
// cveinfo should already be initialized by this time
// as EnableSearchExtension is supposed to be called earlier, but let's be sure
if cveInfo == nil {
cveInfo = cveinfo.NewCVEInfo(storeController, log)
}
resConfig = search.GetResolverConfig(log, storeController, cveInfo)
} else {
resConfig = search.GetResolverConfig(log, storeController, nil)
}
graphqlPrefix := router.PathPrefix(constants.ExtSearchPrefix).Methods("OPTIONS", "GET", "POST")
graphqlPrefix.Handler(gqlHandler.NewDefaultServer(gql_generated.NewExecutableSchema(resConfig)))
}
}
func getExtension(name, url, description string, endpoints []string) distext.Extension {
return distext.Extension{
Name: name,
URL: url,
Description: description,
Endpoints: endpoints,
}
}
func GetExtensions(config *config.Config) distext.ExtensionList {
extensionList := distext.ExtensionList{}
extensions := make([]distext.Extension, 0)
if config.Extensions != nil && config.Extensions.Search != nil {
endpoints := []string{constants.ExtSearchPrefix}
searchExt := getExtension("_zot",
"https://github.com/project-zot/zot/tree/main/pkg/extensions/_zot.md",
"zot registry extension",
endpoints)
extensions = append(extensions, searchExt)
}
extensionList.Extensions = extensions
return extensionList
}