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

feat(cve): expand search domain to cve description and package info (#2086)

* feat(cve): add reference url for cve

Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>

* feat(cve): expand search domain to cve description and package info

Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>

---------

Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
LaurentiuNiculae 2023-11-29 20:59:00 +02:00 committed by GitHub
parent e59d8da454
commit 90d27ff2ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 124 additions and 7 deletions

2
go.mod
View file

@ -496,7 +496,7 @@ require (
go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/mod v0.13.0 // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/term v0.14.0 // indirect

View file

@ -8,6 +8,7 @@ import (
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/exp/slices"
zerr "zotregistry.io/zot/errors"
zcommon "zotregistry.io/zot/pkg/common"
@ -334,7 +335,15 @@ func filterCVEList(cveMap map[string]cvemodel.CVE, searchedCVE string, pageFinde
for _, cve := range cveMap {
if strings.Contains(strings.ToUpper(cve.Title), searchedCVE) ||
strings.Contains(strings.ToUpper(cve.ID), searchedCVE) {
strings.Contains(strings.ToUpper(cve.ID), searchedCVE) ||
strings.Contains(strings.ToUpper(cve.Description), searchedCVE) ||
strings.Contains(strings.ToUpper(cve.Reference), searchedCVE) ||
strings.Contains(strings.ToUpper(cve.Severity), searchedCVE) ||
slices.ContainsFunc(cve.PackageList, func(pack cvemodel.Package) bool {
return strings.Contains(strings.ToUpper(pack.Name), searchedCVE) ||
strings.Contains(strings.ToUpper(pack.FixedVersion), searchedCVE) ||
strings.Contains(strings.ToUpper(pack.InstalledVersion), searchedCVE)
}) {
pageFinder.Add(cve)
}
}

View file

@ -17,6 +17,7 @@ type CVE struct {
Description string `json:"Description"`
Severity string `json:"Severity"`
Title string `json:"Title"`
Reference string `json:"Reference"`
PackageList []Package `json:"PackageList"`
}

View file

@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path"
"strings"
"sync"
"github.com/aquasecurity/trivy-db/pkg/metadata"
@ -427,6 +428,7 @@ func (scanner Scanner) scanManifest(ctx context.Context, repo, digest string) (m
ID: vulnerability.VulnerabilityID,
Title: vulnerability.Title,
Description: vulnerability.Description,
Reference: getCVEReference(vulnerability.PrimaryURL, vulnerability.References),
Severity: convertSeverity(vulnerability.Severity),
PackageList: newPkgList,
}
@ -439,6 +441,34 @@ func (scanner Scanner) scanManifest(ctx context.Context, repo, digest string) (m
return cveidMap, nil
}
func getCVEReference(primaryURL string, references []string) string {
if primaryURL != "" {
return primaryURL
}
if len(references) > 0 {
nvdReference, found := getNVDReference(references)
if found {
return nvdReference
}
return references[0]
}
return ""
}
func getNVDReference(references []string) (string, bool) {
for i := range references {
if strings.Contains(references[i], "nvd.nist.gov") {
return references[i], true
}
}
return "", false
}
func (scanner Scanner) scanIndex(ctx context.Context, repo, digest string) (map[string]cvemodel.CVE, error) {
if cachedMap := scanner.cache.Get(digest); cachedMap != nil {
return cachedMap, nil

View file

@ -488,3 +488,19 @@ func TestIsIndexScannableErrors(t *testing.T) {
})
})
}
func TestGetCVEReference(t *testing.T) {
Convey("getCVEReference", t, func() {
ref := getCVEReference("primary", []string{})
So(ref, ShouldResemble, "primary")
ref = getCVEReference("", []string{"secondary"})
So(ref, ShouldResemble, "secondary")
ref = getCVEReference("", []string{""})
So(ref, ShouldResemble, "")
ref = getCVEReference("", []string{"https://nvd.nist.gov/vuln/detail/CVE-2023-2650"})
So(ref, ShouldResemble, "https://nvd.nist.gov/vuln/detail/CVE-2023-2650")
})
}

View file

@ -54,6 +54,7 @@ type ComplexityRoot struct {
Description func(childComplexity int) int
ID func(childComplexity int) int
PackageList func(childComplexity int) int
Reference func(childComplexity int) int
Severity func(childComplexity int) int
Title func(childComplexity int) int
}
@ -281,6 +282,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.CVE.PackageList(childComplexity), true
case "CVE.Reference":
if e.complexity.CVE.Reference == nil {
break
}
return e.complexity.CVE.Reference(childComplexity), true
case "CVE.Severity":
if e.complexity.CVE.Severity == nil {
break
@ -1184,6 +1192,10 @@ type CVE {
"""
Description: String
"""
Reference for the given CVE
"""
Reference: String
"""
The impact the CVE has, one of "UNKNOWN", "LOW", "MEDIUM", "HIGH", "CRITICAL"
"""
Severity: String
@ -2510,6 +2522,47 @@ func (ec *executionContext) fieldContext_CVE_Description(ctx context.Context, fi
return fc, nil
}
func (ec *executionContext) _CVE_Reference(ctx context.Context, field graphql.CollectedField, obj *Cve) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_CVE_Reference(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Reference, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_CVE_Reference(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "CVE",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _CVE_Severity(ctx context.Context, field graphql.CollectedField, obj *Cve) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_CVE_Severity(ctx, field)
if err != nil {
@ -2683,6 +2736,8 @@ func (ec *executionContext) fieldContext_CVEResultForImage_CVEList(ctx context.C
return ec.fieldContext_CVE_Title(ctx, field)
case "Description":
return ec.fieldContext_CVE_Description(ctx, field)
case "Reference":
return ec.fieldContext_CVE_Reference(ctx, field)
case "Severity":
return ec.fieldContext_CVE_Severity(ctx, field)
case "PackageList":
@ -9407,6 +9462,8 @@ func (ec *executionContext) _CVE(ctx context.Context, sel ast.SelectionSet, obj
out.Values[i] = ec._CVE_Title(ctx, field, obj)
case "Description":
out.Values[i] = ec._CVE_Description(ctx, field, obj)
case "Reference":
out.Values[i] = ec._CVE_Reference(ctx, field, obj)
case "Severity":
out.Values[i] = ec._CVE_Severity(ctx, field, obj)
case "PackageList":

View file

@ -27,6 +27,8 @@ type Cve struct {
Title *string `json:"Title,omitempty"`
// A detailed description of the CVE
Description *string `json:"Description,omitempty"`
// Reference for the given CVE
Reference *string `json:"Reference,omitempty"`
// The impact the CVE has, one of "UNKNOWN", "LOW", "MEDIUM", "HIGH", "CRITICAL"
Severity *string `json:"Severity,omitempty"`
// Information on the packages in which the CVE was found

View file

@ -228,6 +228,7 @@ func getCVEListForImage(
desc := cveDetail.Description
title := cveDetail.Title
severity := cveDetail.Severity
referenceURL := cveDetail.Reference
pkgList := make([]*gql_generated.PackageInfo, 0)
@ -249,6 +250,7 @@ func getCVEListForImage(
Title: &title,
Description: &desc,
Severity: &severity,
Reference: &referenceURL,
PackageList: pkgList,
},
)

View file

@ -46,6 +46,10 @@ type CVE {
"""
Description: String
"""
Reference for the given CVE
"""
Reference: String
"""
The impact the CVE has, one of "UNKNOWN", "LOW", "MEDIUM", "HIGH", "CRITICAL"
"""
Severity: String

View file

@ -20,11 +20,7 @@ func (r *queryResolver) CVEListForImage(ctx context.Context, image string, reque
return &gql_generated.CVEResultForImage{}, zerr.ErrCVESearchDisabled
}
if searchedCve == nil {
return getCVEListForImage(ctx, image, r.cveInfo, requestedPage, "", r.log)
}
return getCVEListForImage(ctx, image, r.cveInfo, requestedPage, *searchedCve, r.log)
return getCVEListForImage(ctx, image, r.cveInfo, requestedPage, deref(searchedCve, ""), r.log)
}
// ImageListForCve is the resolver for the ImageListForCVE field.