mirror of
https://github.com/project-zot/zot.git
synced 2025-03-11 02:17:43 -05:00
Added support for searching fixed tag given cve and an image
This commit is contained in:
parent
72ae02ca4b
commit
ed254159a0
7 changed files with 543 additions and 3 deletions
|
@ -35,4 +35,5 @@ var (
|
|||
ErrNoURLProvided = errors.New("cli: no URL provided in argument or via config. see 'zot config -h'")
|
||||
ErrIllegalConfigKey = errors.New("cli: given config key is not allowed")
|
||||
ErrScanNotSupported = errors.New("search: scanning of image media type not supported")
|
||||
ErrFixedTagNotFound = errors.New("search: no fixed tag found")
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/anuvu/zot/errors"
|
||||
|
@ -130,3 +131,96 @@ func getImageDir(imageName string) string {
|
|||
|
||||
return imageDir
|
||||
}
|
||||
|
||||
// GetImageTagsWithTimestamp returns a list of image tags with timestamp available in the specified repository.
|
||||
func (cveinfo CveInfo) GetImageTagsWithTimestamp(rootDir string, repo string) ([]TagInfo, error) {
|
||||
dir := path.Join(rootDir, repo)
|
||||
if !dirExists(dir) {
|
||||
return nil, errors.ErrRepoNotFound
|
||||
}
|
||||
|
||||
var digest godigest.Digest
|
||||
|
||||
buf, err := ioutil.ReadFile(path.Join(dir, "index.json"))
|
||||
if err != nil {
|
||||
cveinfo.Log.Error().Err(err).Str("dir", dir).Msg("failed to read index.json")
|
||||
return nil, errors.ErrRepoNotFound
|
||||
}
|
||||
|
||||
var index ispec.Index
|
||||
if err := json.Unmarshal(buf, &index); err != nil {
|
||||
cveinfo.Log.Error().Err(err).Str("dir", dir).Msg("invalid JSON")
|
||||
return nil, errors.ErrRepoNotFound
|
||||
}
|
||||
|
||||
tagsInfo := make([]TagInfo, 0)
|
||||
|
||||
var blobIndex ispec.Manifest
|
||||
|
||||
var layerIndex ispec.Image
|
||||
|
||||
for _, manifest := range index.Manifests {
|
||||
digest = manifest.Digest
|
||||
v, ok := manifest.Annotations[ispec.AnnotationRefName]
|
||||
|
||||
blobBuf, err := ioutil.ReadFile(path.Join(dir, "blobs", digest.Algorithm().String(), digest.Encoded()))
|
||||
if err != nil {
|
||||
cveinfo.Log.Error().Err(err).Msg("Unable to open Image Metadata file")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(blobBuf, &blobIndex); err != nil {
|
||||
cveinfo.Log.Error().Err(err).Msg("Unable to marshal blob index")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
digest = blobIndex.Config.Digest
|
||||
|
||||
blobBuf, err = ioutil.ReadFile(path.Join(dir, "blobs", digest.Algorithm().String(), digest.Encoded()))
|
||||
if err != nil {
|
||||
cveinfo.Log.Error().Err(err).Msg("Unable to open Image Layers file")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(blobBuf, &layerIndex); err != nil {
|
||||
cveinfo.Log.Error().Err(err).Msg("Unable to marshal blob index")
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timeStamp := *layerIndex.History[0].Created
|
||||
|
||||
if ok {
|
||||
tagsInfo = append(tagsInfo, TagInfo{Name: v, Timestamp: timeStamp})
|
||||
}
|
||||
}
|
||||
|
||||
return tagsInfo, nil
|
||||
}
|
||||
|
||||
func GetFixedTags(allTags []TagInfo, infectedTags []TagInfo) []TagInfo {
|
||||
sort.Slice(allTags, func(i, j int) bool {
|
||||
return allTags[i].Timestamp.Before(allTags[j].Timestamp)
|
||||
})
|
||||
|
||||
latestInfected := TagInfo{}
|
||||
|
||||
for _, tag := range infectedTags {
|
||||
if !tag.Timestamp.Before(latestInfected.Timestamp) {
|
||||
latestInfected = tag
|
||||
}
|
||||
}
|
||||
|
||||
var fixedTags []TagInfo
|
||||
|
||||
for _, tag := range allTags {
|
||||
if tag.Timestamp.After(latestInfected.Timestamp) {
|
||||
fixedTags = append(fixedTags, tag)
|
||||
}
|
||||
}
|
||||
|
||||
return fixedTags
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
package cveinfo
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/anuvu/zot/pkg/log"
|
||||
config "github.com/aquasecurity/trivy/integration/config"
|
||||
)
|
||||
|
@ -11,3 +13,8 @@ type CveInfo struct {
|
|||
Log log.Logger
|
||||
CveTrivyConfig *config.Config
|
||||
}
|
||||
|
||||
type TagInfo struct {
|
||||
Name string
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/introspection"
|
||||
|
@ -61,6 +62,10 @@ type ComplexityRoot struct {
|
|||
Tags func(childComplexity int) int
|
||||
}
|
||||
|
||||
ImgResultForFixedCve struct {
|
||||
Tags func(childComplexity int) int
|
||||
}
|
||||
|
||||
PackageInfo struct {
|
||||
FixedVersion func(childComplexity int) int
|
||||
InstalledVersion func(childComplexity int) int
|
||||
|
@ -68,14 +73,21 @@ type ComplexityRoot struct {
|
|||
}
|
||||
|
||||
Query struct {
|
||||
CVEListForImage func(childComplexity int, image string) int
|
||||
ImageListForCve func(childComplexity int, id string) int
|
||||
CVEListForImage func(childComplexity int, image string) int
|
||||
ImageListForCve func(childComplexity int, id string) int
|
||||
ImageListWithCVEFixed func(childComplexity int, id string, image string) int
|
||||
}
|
||||
|
||||
TagInfo struct {
|
||||
Name func(childComplexity int) int
|
||||
Timestamp func(childComplexity int) int
|
||||
}
|
||||
}
|
||||
|
||||
type QueryResolver interface {
|
||||
CVEListForImage(ctx context.Context, image string) (*CVEResultForImage, error)
|
||||
ImageListForCve(ctx context.Context, id string) ([]*ImgResultForCve, error)
|
||||
ImageListWithCVEFixed(ctx context.Context, id string, image string) (*ImgResultForFixedCve, error)
|
||||
}
|
||||
|
||||
type executableSchema struct {
|
||||
|
@ -156,6 +168,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.ImgResultForCve.Tags(childComplexity), true
|
||||
|
||||
case "ImgResultForFixedCVE.Tags":
|
||||
if e.complexity.ImgResultForFixedCve.Tags == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.ImgResultForFixedCve.Tags(childComplexity), true
|
||||
|
||||
case "PackageInfo.FixedVersion":
|
||||
if e.complexity.PackageInfo.FixedVersion == nil {
|
||||
break
|
||||
|
@ -201,6 +220,32 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.Query.ImageListForCve(childComplexity, args["id"].(string)), true
|
||||
|
||||
case "Query.ImageListWithCVEFixed":
|
||||
if e.complexity.Query.ImageListWithCVEFixed == nil {
|
||||
break
|
||||
}
|
||||
|
||||
args, err := ec.field_Query_ImageListWithCVEFixed_args(context.TODO(), rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return e.complexity.Query.ImageListWithCVEFixed(childComplexity, args["id"].(string), args["image"].(string)), true
|
||||
|
||||
case "TagInfo.Name":
|
||||
if e.complexity.TagInfo.Name == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.TagInfo.Name(childComplexity), true
|
||||
|
||||
case "TagInfo.Timestamp":
|
||||
if e.complexity.TagInfo.Timestamp == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.TagInfo.Timestamp(childComplexity), true
|
||||
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
@ -251,7 +296,9 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er
|
|||
}
|
||||
|
||||
var sources = []*ast.Source{
|
||||
{Name: "schema.graphql", Input: `type CVEResultForImage {
|
||||
{Name: "schema.graphql", Input: `scalar Time
|
||||
|
||||
type CVEResultForImage {
|
||||
Tag: String
|
||||
CVEList: [CVE]
|
||||
}
|
||||
|
@ -275,9 +322,19 @@ type ImgResultForCVE {
|
|||
Tags: [String]
|
||||
}
|
||||
|
||||
type ImgResultForFixedCVE {
|
||||
Tags: [TagInfo]
|
||||
}
|
||||
|
||||
type TagInfo {
|
||||
Name: String
|
||||
Timestamp: Time
|
||||
}
|
||||
|
||||
type Query {
|
||||
CVEListForImage(image: String!) :CVEResultForImage
|
||||
ImageListForCVE(id: String!) :[ImgResultForCVE]
|
||||
ImageListWithCVEFixed(id: String!, image: String!) :ImgResultForFixedCVE
|
||||
}`, BuiltIn: false},
|
||||
}
|
||||
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||
|
@ -361,6 +418,30 @@ func (ec *executionContext) field_Query_ImageListForCVE_args(ctx context.Context
|
|||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Query_ImageListWithCVEFixed_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
var arg0 string
|
||||
if tmp, ok := rawArgs["id"]; ok {
|
||||
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("id"))
|
||||
arg0, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["id"] = arg0
|
||||
var arg1 string
|
||||
if tmp, ok := rawArgs["image"]; ok {
|
||||
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField("image"))
|
||||
arg1, err = ec.unmarshalNString2string(ctx, tmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
args["image"] = arg1
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
||||
var err error
|
||||
args := map[string]interface{}{}
|
||||
|
@ -708,6 +789,34 @@ func (ec *executionContext) _ImgResultForCVE_Tags(ctx context.Context, field gra
|
|||
return ec.marshalOString2ᚕᚖstring(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ImgResultForFixedCVE_Tags(ctx context.Context, field graphql.CollectedField, obj *ImgResultForFixedCve) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "ImgResultForFixedCVE",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Tags, nil
|
||||
})
|
||||
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.([]*TagInfo)
|
||||
fc.Result = res
|
||||
return ec.marshalOTagInfo2ᚕᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐTagInfo(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _PackageInfo_Name(ctx context.Context, field graphql.CollectedField, obj *PackageInfo) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
@ -862,6 +971,41 @@ func (ec *executionContext) _Query_ImageListForCVE(ctx context.Context, field gr
|
|||
return ec.marshalOImgResultForCVE2ᚕᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐImgResultForCve(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Query_ImageListWithCVEFixed(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "Query",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: true,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
rawArgs := field.ArgumentMap(ec.Variables)
|
||||
args, err := ec.field_Query_ImageListWithCVEFixed_args(ctx, rawArgs)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
fc.Args = args
|
||||
resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return ec.resolvers.Query().ImageListWithCVEFixed(rctx, args["id"].(string), args["image"].(string))
|
||||
})
|
||||
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*ImgResultForFixedCve)
|
||||
fc.Result = res
|
||||
return ec.marshalOImgResultForFixedCVE2ᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐImgResultForFixedCve(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
@ -925,6 +1069,62 @@ func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.C
|
|||
return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _TagInfo_Name(ctx context.Context, field graphql.CollectedField, obj *TagInfo) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "TagInfo",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Name, nil
|
||||
})
|
||||
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*string)
|
||||
fc.Result = res
|
||||
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) _TagInfo_Timestamp(ctx context.Context, field graphql.CollectedField, obj *TagInfo) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = graphql.Null
|
||||
}
|
||||
}()
|
||||
fc := &graphql.FieldContext{
|
||||
Object: "TagInfo",
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: false,
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) {
|
||||
ctx = rctx // use context from middleware stack in children
|
||||
return obj.Timestamp, nil
|
||||
})
|
||||
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*time.Time)
|
||||
fc.Result = res
|
||||
return ec.marshalOTime2ᚖtimeᚐTime(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
@ -1976,6 +2176,30 @@ func (ec *executionContext) _ImgResultForCVE(ctx context.Context, sel ast.Select
|
|||
return out
|
||||
}
|
||||
|
||||
var imgResultForFixedCVEImplementors = []string{"ImgResultForFixedCVE"}
|
||||
|
||||
func (ec *executionContext) _ImgResultForFixedCVE(ctx context.Context, sel ast.SelectionSet, obj *ImgResultForFixedCve) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, imgResultForFixedCVEImplementors)
|
||||
|
||||
out := graphql.NewFieldSet(fields)
|
||||
var invalids uint32
|
||||
for i, field := range fields {
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("ImgResultForFixedCVE")
|
||||
case "Tags":
|
||||
out.Values[i] = ec._ImgResultForFixedCVE_Tags(ctx, field, obj)
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch()
|
||||
if invalids > 0 {
|
||||
return graphql.Null
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var packageInfoImplementors = []string{"PackageInfo"}
|
||||
|
||||
func (ec *executionContext) _PackageInfo(ctx context.Context, sel ast.SelectionSet, obj *PackageInfo) graphql.Marshaler {
|
||||
|
@ -2041,6 +2265,17 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
|
|||
res = ec._Query_ImageListForCVE(ctx, field)
|
||||
return res
|
||||
})
|
||||
case "ImageListWithCVEFixed":
|
||||
field := field
|
||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
}
|
||||
}()
|
||||
res = ec._Query_ImageListWithCVEFixed(ctx, field)
|
||||
return res
|
||||
})
|
||||
case "__type":
|
||||
out.Values[i] = ec._Query___type(ctx, field)
|
||||
case "__schema":
|
||||
|
@ -2056,6 +2291,32 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr
|
|||
return out
|
||||
}
|
||||
|
||||
var tagInfoImplementors = []string{"TagInfo"}
|
||||
|
||||
func (ec *executionContext) _TagInfo(ctx context.Context, sel ast.SelectionSet, obj *TagInfo) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, tagInfoImplementors)
|
||||
|
||||
out := graphql.NewFieldSet(fields)
|
||||
var invalids uint32
|
||||
for i, field := range fields {
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString("TagInfo")
|
||||
case "Name":
|
||||
out.Values[i] = ec._TagInfo_Name(ctx, field, obj)
|
||||
case "Timestamp":
|
||||
out.Values[i] = ec._TagInfo_Timestamp(ctx, field, obj)
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch()
|
||||
if invalids > 0 {
|
||||
return graphql.Null
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var __DirectiveImplementors = []string{"__Directive"}
|
||||
|
||||
func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler {
|
||||
|
@ -2685,6 +2946,13 @@ func (ec *executionContext) marshalOImgResultForCVE2ᚖgithubᚗcomᚋanuvuᚋzo
|
|||
return ec._ImgResultForCVE(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOImgResultForFixedCVE2ᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐImgResultForFixedCve(ctx context.Context, sel ast.SelectionSet, v *ImgResultForFixedCve) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
return ec._ImgResultForFixedCVE(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOPackageInfo2ᚕᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐPackageInfo(ctx context.Context, sel ast.SelectionSet, v []*PackageInfo) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
|
@ -2792,6 +3060,68 @@ func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel as
|
|||
return graphql.MarshalString(*v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOTagInfo2ᚕᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐTagInfo(ctx context.Context, sel ast.SelectionSet, v []*TagInfo) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
ret := make(graphql.Array, len(v))
|
||||
var wg sync.WaitGroup
|
||||
isLen1 := len(v) == 1
|
||||
if !isLen1 {
|
||||
wg.Add(len(v))
|
||||
}
|
||||
for i := range v {
|
||||
i := i
|
||||
fc := &graphql.FieldContext{
|
||||
Index: &i,
|
||||
Result: &v[i],
|
||||
}
|
||||
ctx := graphql.WithFieldContext(ctx, fc)
|
||||
f := func(i int) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = nil
|
||||
}
|
||||
}()
|
||||
if !isLen1 {
|
||||
defer wg.Done()
|
||||
}
|
||||
ret[i] = ec.marshalOTagInfo2ᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐTagInfo(ctx, sel, v[i])
|
||||
}
|
||||
if isLen1 {
|
||||
f(i)
|
||||
} else {
|
||||
go f(i)
|
||||
}
|
||||
|
||||
}
|
||||
wg.Wait()
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOTagInfo2ᚖgithubᚗcomᚋanuvuᚋzotᚋpkgᚋextensionsᚋsearchᚐTagInfo(ctx context.Context, sel ast.SelectionSet, v *TagInfo) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
return ec._TagInfo(ctx, sel, v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) unmarshalOTime2ᚖtimeᚐTime(ctx context.Context, v interface{}) (*time.Time, error) {
|
||||
if v == nil {
|
||||
return nil, nil
|
||||
}
|
||||
res, err := graphql.UnmarshalTime(v)
|
||||
return &res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalOTime2ᚖtimeᚐTime(ctx context.Context, sel ast.SelectionSet, v *time.Time) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
return graphql.MarshalTime(*v)
|
||||
}
|
||||
|
||||
func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler {
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
package search
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cve struct {
|
||||
ID *string `json:"Id"`
|
||||
Title *string `json:"Title"`
|
||||
|
@ -20,8 +24,17 @@ type ImgResultForCve struct {
|
|||
Tags []*string `json:"Tags"`
|
||||
}
|
||||
|
||||
type ImgResultForFixedCve struct {
|
||||
Tags []*TagInfo `json:"Tags"`
|
||||
}
|
||||
|
||||
type PackageInfo struct {
|
||||
Name *string `json:"Name"`
|
||||
InstalledVersion *string `json:"InstalledVersion"`
|
||||
FixedVersion *string `json:"FixedVersion"`
|
||||
}
|
||||
|
||||
type TagInfo struct {
|
||||
Name *string `json:"Name"`
|
||||
Timestamp *time.Time `json:"Timestamp"`
|
||||
}
|
||||
|
|
|
@ -218,3 +218,86 @@ func (r *queryResolver) ImageListForCve(ctx context.Context, id string) ([]*ImgR
|
|||
|
||||
return cveResult, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) ImageListWithCVEFixed(ctx context.Context, id string, image string) (*ImgResultForFixedCve, error) { // nolint: lll
|
||||
imgResultForFixedCVE := &ImgResultForFixedCve{}
|
||||
|
||||
r.cveInfo.Log.Info().Str("Extracting list of tags available in image", image).Msg("")
|
||||
|
||||
isValidImage, err := r.cveInfo.IsValidImageFormat(path.Join(r.dir, image))
|
||||
if !isValidImage {
|
||||
r.cveInfo.Log.Debug().Msg("Image media type not supported for scanning")
|
||||
|
||||
return imgResultForFixedCVE, errors.ErrScanNotSupported
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return imgResultForFixedCVE, err
|
||||
}
|
||||
|
||||
tagsInfo, err := r.cveInfo.GetImageTagsWithTimestamp(r.dir, image)
|
||||
if err != nil {
|
||||
r.cveInfo.Log.Error().Err(err).Msg("Error while readling image media type")
|
||||
|
||||
return imgResultForFixedCVE, err
|
||||
}
|
||||
|
||||
infectedTags := make([]cveinfo.TagInfo, 0)
|
||||
|
||||
var hasCVE bool
|
||||
|
||||
for _, tag := range tagsInfo {
|
||||
r.cveInfo.CveTrivyConfig.TrivyConfig.Input = path.Join(r.dir, image+":"+tag.Name)
|
||||
|
||||
r.cveInfo.Log.Info().Str("Scanning image", path.Join(r.dir, image+":"+tag.Name)).Msg("")
|
||||
|
||||
results, err := cveinfo.ScanImage(r.cveInfo.CveTrivyConfig)
|
||||
if err != nil {
|
||||
r.cveInfo.Log.Error().Err(err).Str("Error scanning image", image+":"+tag.Name).Msg("")
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
hasCVE = false
|
||||
|
||||
for _, result := range results {
|
||||
for _, vulnerability := range result.Vulnerabilities {
|
||||
if vulnerability.VulnerabilityID == id {
|
||||
hasCVE = true
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hasCVE {
|
||||
infectedTags = append(infectedTags, cveinfo.TagInfo{Name: tag.Name, Timestamp: tag.Timestamp})
|
||||
}
|
||||
}
|
||||
|
||||
if len(infectedTags) != 0 {
|
||||
r.cveInfo.Log.Info().Msg("Comparing fixed tags timestamp")
|
||||
|
||||
fixedTags := cveinfo.GetFixedTags(tagsInfo, infectedTags)
|
||||
|
||||
finalTagList := make([]*TagInfo, 0)
|
||||
|
||||
for _, tag := range fixedTags {
|
||||
copyTag := tag.Name
|
||||
|
||||
copyTimeStamp := tag.Timestamp
|
||||
|
||||
finalTagList = append(finalTagList, &TagInfo{Name: ©Tag, Timestamp: ©TimeStamp})
|
||||
}
|
||||
|
||||
imgResultForFixedCVE = &ImgResultForFixedCve{Tags: finalTagList}
|
||||
|
||||
return imgResultForFixedCVE, nil
|
||||
}
|
||||
|
||||
r.cveInfo.Log.Info().Msg("Input image does not contain any tag that does not have given cve")
|
||||
|
||||
imgResultForFixedCVE = &ImgResultForFixedCve{}
|
||||
|
||||
return imgResultForFixedCVE, errors.ErrFixedTagNotFound
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
scalar Time
|
||||
|
||||
type CVEResultForImage {
|
||||
Tag: String
|
||||
CVEList: [CVE]
|
||||
|
@ -22,7 +24,17 @@ type ImgResultForCVE {
|
|||
Tags: [String]
|
||||
}
|
||||
|
||||
type ImgResultForFixedCVE {
|
||||
Tags: [TagInfo]
|
||||
}
|
||||
|
||||
type TagInfo {
|
||||
Name: String
|
||||
Timestamp: Time
|
||||
}
|
||||
|
||||
type Query {
|
||||
CVEListForImage(image: String!) :CVEResultForImage
|
||||
ImageListForCVE(id: String!) :[ImgResultForCVE]
|
||||
ImageListWithCVEFixed(id: String!, image: String!) :ImgResultForFixedCVE
|
||||
}
|
Loading…
Add table
Reference in a new issue