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:
parent
e59d8da454
commit
90d27ff2ac
10 changed files with 124 additions and 7 deletions
2
go.mod
2
go.mod
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue