2022-10-10 07:05:55 -05:00
//go:build search
// +build search
2020-10-14 16:47:20 -05:00
package extensions
import (
"time"
gqlHandler "github.com/99designs/gqlgen/graphql/handler"
2021-10-15 10:05:00 -05:00
"github.com/gorilla/mux"
2022-02-24 15:31:36 -05:00
distext "github.com/opencontainers/distribution-spec/specs-go/v1/extensions"
2022-10-20 11:39:20 -05:00
2021-12-03 22:50:58 -05:00
"zotregistry.io/zot/pkg/api/config"
2022-02-24 15:31:36 -05:00
"zotregistry.io/zot/pkg/api/constants"
2021-12-03 22:50:58 -05:00
"zotregistry.io/zot/pkg/extensions/search"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
2022-07-15 06:10:51 -05:00
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
2021-12-03 22:50:58 -05:00
"zotregistry.io/zot/pkg/log"
2023-01-09 15:37:44 -05:00
"zotregistry.io/zot/pkg/meta/repodb"
2021-12-03 22:50:58 -05:00
"zotregistry.io/zot/pkg/storage"
2020-10-14 16:47:20 -05:00
)
2022-09-28 13:39:54 -05:00
// 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.
2022-10-05 05:21:14 -05:00
var cveInfo cveinfo . CveInfo //nolint:gochecknoglobals
2022-09-28 13:39:54 -05:00
2023-01-09 15:37:44 -05:00
func EnableSearchExtension ( config * config . Config , storeController storage . StoreController ,
repoDB repodb . RepoDB , log log . Logger ,
) {
2021-12-28 08:29:30 -05:00
if config . Extensions . Search != nil && * config . Extensions . Search . Enable && config . Extensions . Search . CVE != nil {
2020-10-14 16:47:20 -05:00
defaultUpdateInterval , _ := time . ParseDuration ( "2h" )
2021-06-08 15:11:18 -05:00
if config . Extensions . Search . CVE . UpdateInterval < defaultUpdateInterval {
config . Extensions . Search . CVE . UpdateInterval = defaultUpdateInterval
2020-10-14 16:47:20 -05:00
2022-03-21 12:37:23 -05:00
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
2020-10-14 16:47:20 -05:00
}
2023-01-18 17:18:03 -05:00
dbRepository := ""
if config . Extensions . Search . CVE . Trivy != nil {
dbRepository = config . Extensions . Search . CVE . Trivy . DBRepository
}
cveInfo = cveinfo . NewCVEInfo ( storeController , repoDB , dbRepository , log )
2022-09-28 13:39:54 -05:00
2020-10-14 16:47:20 -05:00
go func ( ) {
2022-09-28 13:39:54 -05:00
err := downloadTrivyDB ( log , config . Extensions . Search . CVE . UpdateInterval )
2020-10-14 16:47:20 -05:00
if err != nil {
2021-06-08 13:37:31 -05:00
log . Error ( ) . Err ( err ) . Msg ( "error while downloading TrivyDB" )
2020-10-14 16:47:20 -05:00
}
} ( )
} else {
2020-10-22 19:31:16 -05:00
log . Info ( ) . Msg ( "CVE config not provided, skipping CVE update" )
2020-10-14 16:47:20 -05:00
}
2022-04-27 01:00:20 -05:00
}
2021-06-08 15:11:18 -05:00
2022-09-28 13:39:54 -05:00
func downloadTrivyDB ( log log . Logger , updateInterval time . Duration ) error {
2022-04-27 01:00:20 -05:00
for {
log . Info ( ) . Msg ( "updating the CVE database" )
2021-10-28 04:10:01 -05:00
2022-09-28 13:39:54 -05:00
err := cveInfo . UpdateDB ( )
2022-04-27 01:00:20 -05:00
if err != nil {
return err
2021-10-28 04:10:01 -05:00
}
2022-04-27 01:00:20 -05:00
log . Info ( ) . Str ( "DB update completed, next update scheduled after" , updateInterval . String ( ) ) . Msg ( "" )
time . Sleep ( updateInterval )
2021-06-08 15:11:18 -05:00
}
2020-10-14 16:47:20 -05:00
}
2022-04-27 01:00:20 -05:00
func SetupSearchRoutes ( config * config . Config , router * mux . Router , storeController storage . StoreController ,
2023-01-09 15:37:44 -05:00
repoDB repodb . RepoDB , log log . Logger ,
2022-04-27 01:00:20 -05:00
) {
log . Info ( ) . Msg ( "setting up search routes" )
2022-03-04 02:37:06 -05:00
2022-04-27 01:00:20 -05:00
if config . Extensions . Search != nil && * config . Extensions . Search . Enable {
2022-07-15 06:10:51 -05:00
var resConfig gql_generated . Config
2022-03-04 02:37:06 -05:00
2022-04-27 01:00:20 -05:00
if config . Extensions . Search . CVE != nil {
2022-09-28 13:39:54 -05:00
// cveinfo should already be initialized by this time
// as EnableSearchExtension is supposed to be called earlier, but let's be sure
if cveInfo == nil {
2023-01-18 17:18:03 -05:00
dbRepository := ""
if config . Extensions . Search . CVE . Trivy != nil {
dbRepository = config . Extensions . Search . CVE . Trivy . DBRepository
}
cveInfo = cveinfo . NewCVEInfo ( storeController , repoDB , dbRepository , log )
2022-09-28 13:39:54 -05:00
}
2023-01-09 15:37:44 -05:00
resConfig = search . GetResolverConfig ( log , storeController , repoDB , cveInfo )
2022-05-09 17:30:11 -05:00
} else {
2023-01-09 15:37:44 -05:00
resConfig = search . GetResolverConfig ( log , storeController , repoDB , nil )
2022-05-09 17:30:11 -05:00
}
2022-04-27 01:00:20 -05:00
2022-10-18 22:46:06 -05:00
graphqlPrefix := router . PathPrefix ( constants . FullSearchPrefix ) . Methods ( "OPTIONS" , "GET" , "POST" )
2022-08-16 03:57:09 -05:00
graphqlPrefix . Handler ( gqlHandler . NewDefaultServer ( gql_generated . NewExecutableSchema ( resConfig ) ) )
2022-03-04 02:37:06 -05:00
}
}
2022-05-23 14:22:52 -05:00
func getExtension ( name , url , description string , endpoints [ ] string ) distext . Extension {
2022-02-24 15:31:36 -05:00
return distext . Extension {
Name : name ,
URL : url ,
Description : description ,
2022-05-23 14:22:52 -05:00
Endpoints : endpoints ,
2022-02-24 15:31:36 -05:00
}
}
func GetExtensions ( config * config . Config ) distext . ExtensionList {
extensionList := distext . ExtensionList { }
extensions := make ( [ ] distext . Extension , 0 )
if config . Extensions != nil && config . Extensions . Search != nil {
2022-10-18 22:46:06 -05:00
endpoints := [ ] string { constants . FullSearchPrefix }
2022-05-25 12:49:22 -05:00
searchExt := getExtension ( "_zot" ,
2022-10-11 11:01:59 -05:00
"https://github.com/project-zot/zot/blob/" + config . ReleaseTag + "/pkg/extensions/_zot.md" ,
"zot registry extensions" ,
2022-05-25 12:49:22 -05:00
endpoints )
2022-02-24 15:31:36 -05:00
extensions = append ( extensions , searchExt )
}
extensionList . Extensions = extensions
return extensionList
}