mirror of
https://github.com/project-zot/zot.git
synced 2026-06-16 04:17:55 +08:00
Added graphql api feature for image vulnerability scanning
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"generated.go",
|
||||
"models_gen.go",
|
||||
"resolver.go",
|
||||
],
|
||||
importpath = "github.com/anuvu/zot/pkg/extensions/search",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//pkg/extensions/search/cve:go_default_library",
|
||||
"//pkg/log:go_default_library",
|
||||
"//pkg/storage:go_default_library",
|
||||
"@com_github_99designs_gqlgen//graphql:go_default_library",
|
||||
"@com_github_99designs_gqlgen//graphql/introspection:go_default_library",
|
||||
"@com_github_vektah_gqlparser_v2//:go_default_library",
|
||||
"@com_github_vektah_gqlparser_v2//ast:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -12,6 +12,7 @@ go_library(
|
||||
"//pkg/log:go_default_library",
|
||||
"@com_github_aquasecurity_trivy//integration:go_default_library",
|
||||
"@com_github_aquasecurity_trivy//integration/config:go_default_library",
|
||||
"@com_github_aquasecurity_trivy//pkg/report:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/anuvu/zot/pkg/log"
|
||||
integration "github.com/aquasecurity/trivy/integration"
|
||||
config "github.com/aquasecurity/trivy/integration/config"
|
||||
"github.com/aquasecurity/trivy/pkg/report"
|
||||
)
|
||||
|
||||
// UpdateCVEDb ...
|
||||
@@ -22,3 +23,11 @@ func UpdateCVEDb(dbDir string, log log.Logger) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewTrivyConfig(dir string) (*config.Config, error) {
|
||||
return config.NewConfig(dir)
|
||||
}
|
||||
|
||||
func ScanImage(config *config.Config) (report.Results, error) {
|
||||
return integration.ScanTrivyImage(config.TrivyConfig)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,27 @@
|
||||
// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
|
||||
|
||||
package search
|
||||
|
||||
type Cve struct {
|
||||
ID *string `json:"Id"`
|
||||
Title *string `json:"Title"`
|
||||
Description *string `json:"Description"`
|
||||
Severity *string `json:"Severity"`
|
||||
PackageList []*PackageInfo `json:"PackageList"`
|
||||
}
|
||||
|
||||
type CVEResultForImage struct {
|
||||
Tag *string `json:"Tag"`
|
||||
CVEList []*Cve `json:"CVEList"`
|
||||
}
|
||||
|
||||
type ImgResultForCve struct {
|
||||
Name *string `json:"Name"`
|
||||
Tags []*string `json:"Tags"`
|
||||
}
|
||||
|
||||
type PackageInfo struct {
|
||||
Name *string `json:"Name"`
|
||||
InstalledVersion *string `json:"InstalledVersion"`
|
||||
FixedVersion *string `json:"FixedVersion"`
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
package search
|
||||
|
||||
//go:generate go run github.com/99designs/gqlgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/anuvu/zot/pkg/log"
|
||||
|
||||
cveinfo "github.com/anuvu/zot/pkg/extensions/search/cve"
|
||||
"github.com/anuvu/zot/pkg/storage"
|
||||
) // THIS CODE IS A STARTING POINT ONLY. IT WILL NOT BE UPDATED WITH SCHEMA CHANGES.
|
||||
|
||||
// Resolver ...
|
||||
type Resolver struct {
|
||||
cveInfo *cveinfo.CveInfo
|
||||
imgStore *storage.ImageStore
|
||||
dir string
|
||||
}
|
||||
|
||||
// Query ...
|
||||
func (r *Resolver) Query() QueryResolver {
|
||||
return &queryResolver{r}
|
||||
}
|
||||
|
||||
type queryResolver struct{ *Resolver }
|
||||
|
||||
type cveDetail struct {
|
||||
Title string
|
||||
Description string
|
||||
Severity string
|
||||
PackageList []*PackageInfo
|
||||
}
|
||||
|
||||
// GetResolverConfig ...
|
||||
func GetResolverConfig(dir string, log log.Logger, imgstorage *storage.ImageStore) Config {
|
||||
config, err := cveinfo.NewTrivyConfig(dir)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cve := &cveinfo.CveInfo{Log: log, CveTrivyConfig: config}
|
||||
|
||||
resConfig := &Resolver{cveInfo: cve, imgStore: imgstorage, dir: dir}
|
||||
|
||||
return Config{Resolvers: resConfig, Directives: DirectiveRoot{},
|
||||
Complexity: ComplexityRoot{}}
|
||||
}
|
||||
|
||||
func (r *queryResolver) CVEListForImage(ctx context.Context, image string) (*CVEResultForImage, error) {
|
||||
r.cveInfo.CveTrivyConfig.TrivyConfig.Input = path.Join(r.dir, image)
|
||||
|
||||
r.cveInfo.Log.Info().Str("Scanning Image", image).Msg("")
|
||||
|
||||
cveResults, err := cveinfo.ScanImage(r.cveInfo.CveTrivyConfig)
|
||||
if err != nil {
|
||||
r.cveInfo.Log.Error().Err(err).Msg("Error scanning image repository")
|
||||
|
||||
return &CVEResultForImage{}, err
|
||||
}
|
||||
|
||||
var copyImgTag string
|
||||
|
||||
if strings.Contains(image, ":") {
|
||||
copyImgTag = strings.Split(image, ":")[1]
|
||||
}
|
||||
|
||||
cveidMap := make(map[string]cveDetail)
|
||||
|
||||
for _, result := range cveResults {
|
||||
for _, vulnerability := range result.Vulnerabilities {
|
||||
pkgName := vulnerability.PkgName
|
||||
|
||||
installedVersion := vulnerability.InstalledVersion
|
||||
|
||||
var fixedVersion string
|
||||
if vulnerability.FixedVersion != "" {
|
||||
fixedVersion = vulnerability.FixedVersion
|
||||
} else {
|
||||
fixedVersion = "Not Specified"
|
||||
}
|
||||
|
||||
_, ok := cveidMap[vulnerability.VulnerabilityID]
|
||||
if ok {
|
||||
cveDetailStruct := cveidMap[vulnerability.VulnerabilityID]
|
||||
|
||||
pkgList := cveDetailStruct.PackageList
|
||||
|
||||
pkgList = append(pkgList,
|
||||
&PackageInfo{Name: &pkgName, InstalledVersion: &installedVersion, FixedVersion: &fixedVersion})
|
||||
|
||||
cveDetailStruct.PackageList = pkgList
|
||||
|
||||
cveidMap[vulnerability.VulnerabilityID] = cveDetailStruct
|
||||
} else {
|
||||
newPkgList := make([]*PackageInfo, 0)
|
||||
|
||||
newPkgList = append(newPkgList,
|
||||
&PackageInfo{Name: &pkgName, InstalledVersion: &installedVersion, FixedVersion: &fixedVersion})
|
||||
|
||||
cveidMap[vulnerability.VulnerabilityID] = cveDetail{Title: vulnerability.Title,
|
||||
Description: vulnerability.Description, Severity: vulnerability.Severity, PackageList: newPkgList}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cveids := []*Cve{}
|
||||
|
||||
for id, cveDetail := range cveidMap {
|
||||
vulID := id
|
||||
|
||||
desc := cveDetail.Description
|
||||
|
||||
title := cveDetail.Title
|
||||
|
||||
severity := cveDetail.Severity
|
||||
|
||||
pkgList := cveDetail.PackageList
|
||||
|
||||
cveids = append(cveids,
|
||||
&Cve{ID: &vulID, Title: &title, Description: &desc, Severity: &severity, PackageList: pkgList})
|
||||
}
|
||||
|
||||
return &CVEResultForImage{Tag: ©ImgTag, CVEList: cveids}, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) ImageListForCve(ctx context.Context, id string) ([]*ImgResultForCve, error) {
|
||||
cveResult := []*ImgResultForCve{}
|
||||
|
||||
r.cveInfo.Log.Info().Msg("Extracting Repositories")
|
||||
|
||||
repoList, err := r.imgStore.GetRepositories()
|
||||
if err != nil {
|
||||
r.cveInfo.Log.Error().Err(err).Msg("Not able to search repositories")
|
||||
|
||||
return cveResult, err
|
||||
}
|
||||
|
||||
r.cveInfo.Log.Info().Msg("Scanning each repository")
|
||||
|
||||
for _, repo := range repoList {
|
||||
r.cveInfo.Log.Info().Str("Extracting list of tags available in image", repo).Msg("")
|
||||
|
||||
if err != nil {
|
||||
r.cveInfo.Log.Error().Err(err).Str("Error reading image media type", repo)
|
||||
|
||||
return cveResult, err
|
||||
}
|
||||
|
||||
tagList, err := r.imgStore.GetImageTags(repo)
|
||||
if err != nil {
|
||||
r.cveInfo.Log.Error().Err(err).Msg("Not able to get list of Image Tag")
|
||||
}
|
||||
|
||||
var name string
|
||||
|
||||
tags := make([]*string, 0)
|
||||
|
||||
for _, tag := range tagList {
|
||||
r.cveInfo.CveTrivyConfig.TrivyConfig.Input = path.Join(r.dir, repo+":"+tag)
|
||||
|
||||
r.cveInfo.Log.Info().Str("Scanning Image", path.Join(r.dir, repo+":"+tag)).Msg("")
|
||||
|
||||
results, err := cveinfo.ScanImage(r.cveInfo.CveTrivyConfig)
|
||||
if err != nil {
|
||||
r.cveInfo.Log.Error().Err(err).Str("Error scanning image", repo+":"+tag)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
name = repo
|
||||
|
||||
for _, result := range results {
|
||||
for _, vulnerability := range result.Vulnerabilities {
|
||||
if vulnerability.VulnerabilityID == id {
|
||||
copyImgTag := tag
|
||||
tags = append(tags, ©ImgTag)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(tags) != 0 {
|
||||
cveResult = append(cveResult, &ImgResultForCve{Name: &name, Tags: tags})
|
||||
}
|
||||
}
|
||||
|
||||
return cveResult, nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
type CVEResultForImage {
|
||||
Tag: String
|
||||
CVEList: [CVE]
|
||||
}
|
||||
|
||||
type CVE {
|
||||
Id: String
|
||||
Title: String
|
||||
Description: String
|
||||
Severity: String
|
||||
PackageList: [PackageInfo]
|
||||
}
|
||||
|
||||
type PackageInfo {
|
||||
Name: String
|
||||
InstalledVersion: String
|
||||
FixedVersion: String
|
||||
}
|
||||
|
||||
type ImgResultForCVE {
|
||||
Name: String
|
||||
Tags: [String]
|
||||
}
|
||||
|
||||
type Query {
|
||||
CVEListForImage(image: String!) :CVEResultForImage
|
||||
ImageListForCVE(id: String!) :[ImgResultForCVE]
|
||||
}
|
||||
Reference in New Issue
Block a user