Added graphql api feature for image vulnerability scanning

This commit is contained in:
Shivam Mishra
2020-06-26 12:09:10 -07:00
parent baa5d247ec
commit 2cf2c16137
14 changed files with 3455 additions and 3 deletions
+21
View File
@@ -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",
],
)
+1
View File
@@ -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",
],
)
+9
View File
@@ -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
+27
View File
@@ -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"`
}
+193
View File
@@ -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: &copyImgTag, 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, &copyImgTag)
break
}
}
}
}
if len(tags) != 0 {
cveResult = append(cveResult, &ImgResultForCve{Name: &name, Tags: tags})
}
}
return cveResult, nil
}
+28
View File
@@ -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]
}