zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/extensions/search/convert/convert_internal_test.go (about)

     1  //go:build search
     2  
     3  package convert
     4  
     5  import (
     6  	"context"
     7  	"errors"
     8  	"testing"
     9  
    10  	"github.com/99designs/gqlgen/graphql"
    11  	ispec "github.com/opencontainers/image-spec/specs-go/v1"
    12  	. "github.com/smartystreets/goconvey/convey"
    13  
    14  	cvemodel "zotregistry.dev/zot/pkg/extensions/search/cve/model"
    15  	"zotregistry.dev/zot/pkg/extensions/search/gql_generated"
    16  	"zotregistry.dev/zot/pkg/log"
    17  	"zotregistry.dev/zot/pkg/meta/boltdb"
    18  	. "zotregistry.dev/zot/pkg/test/image-utils"
    19  	"zotregistry.dev/zot/pkg/test/mocks"
    20  )
    21  
    22  var ErrTestError = errors.New("TestError")
    23  
    24  func TestCVEConvert(t *testing.T) {
    25  	Convey("Test adding CVE information to Summary objects", t, func() {
    26  		params := boltdb.DBParameters{
    27  			RootDir: t.TempDir(),
    28  		}
    29  		boltDB, err := boltdb.GetBoltDriver(params)
    30  		So(err, ShouldBeNil)
    31  
    32  		metaDB, err := boltdb.New(boltDB, log.NewLogger("debug", ""))
    33  		So(err, ShouldBeNil)
    34  
    35  		image := CreateImageWith().
    36  			Layers([]Layer{{
    37  				MediaType: ispec.MediaTypeImageLayerGzip,
    38  				Digest:    ispec.MediaTypeEmptyJSON,
    39  				Blob:      ispec.DescriptorEmptyJSON.Data,
    40  			}}).DefaultConfig().Build()
    41  
    42  		err = metaDB.SetRepoReference(context.Background(), "repo1", "0.1.0", image.AsImageMeta())
    43  		So(err, ShouldBeNil)
    44  
    45  		repoMetaList, err := metaDB.SearchRepos(context.Background(), "")
    46  		So(err, ShouldBeNil)
    47  
    48  		imageMeta, err := metaDB.FilterImageMeta(context.Background(), []string{image.DigestStr()})
    49  
    50  		ctx := graphql.WithResponseContext(context.Background(),
    51  			graphql.DefaultErrorPresenter, graphql.DefaultRecover)
    52  
    53  		Convey("Add CVE Summary to ImageSummary", func() {
    54  			var imageSummary *gql_generated.ImageSummary
    55  
    56  			So(imageSummary, ShouldBeNil)
    57  
    58  			updateImageSummaryVulnerabilities(ctx,
    59  				imageSummary,
    60  				SkipQGLField{
    61  					Vulnerabilities: false,
    62  				},
    63  				mocks.CveInfoMock{
    64  					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
    65  					) (cvemodel.ImageCVESummary, error) {
    66  						return cvemodel.ImageCVESummary{}, ErrTestError
    67  					},
    68  				},
    69  			)
    70  
    71  			So(imageSummary, ShouldBeNil)
    72  			So(graphql.GetErrors(ctx), ShouldBeNil)
    73  
    74  			imageSummary, _, err = ImageManifest2ImageSummary(ctx, GetFullImageMeta("0.1.0", repoMetaList[0],
    75  				imageMeta[image.DigestStr()]))
    76  			So(err, ShouldBeNil)
    77  
    78  			So(imageSummary, ShouldNotBeNil)
    79  			So(imageSummary.Vulnerabilities, ShouldBeNil)
    80  
    81  			updateImageSummaryVulnerabilities(ctx,
    82  				imageSummary,
    83  				SkipQGLField{
    84  					Vulnerabilities: true,
    85  				},
    86  				mocks.CveInfoMock{},
    87  			)
    88  
    89  			So(imageSummary.Vulnerabilities, ShouldNotBeNil)
    90  			So(*imageSummary.Vulnerabilities.Count, ShouldEqual, 0)
    91  			So(*imageSummary.Vulnerabilities.UnknownCount, ShouldEqual, 0)
    92  			So(*imageSummary.Vulnerabilities.LowCount, ShouldEqual, 0)
    93  			So(*imageSummary.Vulnerabilities.MediumCount, ShouldEqual, 0)
    94  			So(*imageSummary.Vulnerabilities.HighCount, ShouldEqual, 0)
    95  			So(*imageSummary.Vulnerabilities.CriticalCount, ShouldEqual, 0)
    96  			So(*imageSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "")
    97  			So(graphql.GetErrors(ctx), ShouldBeNil)
    98  
    99  			imageSummary.Vulnerabilities = nil
   100  
   101  			updateImageSummaryVulnerabilities(ctx,
   102  				imageSummary,
   103  				SkipQGLField{
   104  					Vulnerabilities: false,
   105  				},
   106  				mocks.CveInfoMock{
   107  					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
   108  					) (cvemodel.ImageCVESummary, error) {
   109  						return cvemodel.ImageCVESummary{
   110  							Count:         30,
   111  							UnknownCount:  1,
   112  							LowCount:      2,
   113  							MediumCount:   3,
   114  							HighCount:     10,
   115  							CriticalCount: 14,
   116  							MaxSeverity:   "HIGH",
   117  						}, nil
   118  					},
   119  				},
   120  			)
   121  
   122  			So(imageSummary.Vulnerabilities, ShouldNotBeNil)
   123  			So(*imageSummary.Vulnerabilities.Count, ShouldEqual, 30)
   124  			So(*imageSummary.Vulnerabilities.UnknownCount, ShouldEqual, 1)
   125  			So(*imageSummary.Vulnerabilities.LowCount, ShouldEqual, 2)
   126  			So(*imageSummary.Vulnerabilities.MediumCount, ShouldEqual, 3)
   127  			So(*imageSummary.Vulnerabilities.HighCount, ShouldEqual, 10)
   128  			So(*imageSummary.Vulnerabilities.CriticalCount, ShouldEqual, 14)
   129  			So(*imageSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "HIGH")
   130  			So(graphql.GetErrors(ctx), ShouldBeNil)
   131  			So(len(imageSummary.Manifests), ShouldEqual, 1)
   132  			So(imageSummary.Manifests[0].Vulnerabilities, ShouldNotBeNil)
   133  			So(*imageSummary.Manifests[0].Vulnerabilities.Count, ShouldEqual, 30)
   134  			So(*imageSummary.Manifests[0].Vulnerabilities.UnknownCount, ShouldEqual, 1)
   135  			So(*imageSummary.Manifests[0].Vulnerabilities.LowCount, ShouldEqual, 2)
   136  			So(*imageSummary.Manifests[0].Vulnerabilities.MediumCount, ShouldEqual, 3)
   137  			So(*imageSummary.Manifests[0].Vulnerabilities.HighCount, ShouldEqual, 10)
   138  			So(*imageSummary.Manifests[0].Vulnerabilities.CriticalCount, ShouldEqual, 14)
   139  			So(*imageSummary.Manifests[0].Vulnerabilities.MaxSeverity, ShouldEqual, "HIGH")
   140  
   141  			imageSummary.Vulnerabilities = nil
   142  
   143  			updateImageSummaryVulnerabilities(ctx,
   144  				imageSummary,
   145  				SkipQGLField{
   146  					Vulnerabilities: false,
   147  				},
   148  				mocks.CveInfoMock{
   149  					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
   150  					) (cvemodel.ImageCVESummary, error) {
   151  						return cvemodel.ImageCVESummary{}, ErrTestError
   152  					},
   153  				},
   154  			)
   155  
   156  			So(imageSummary.Vulnerabilities, ShouldNotBeNil)
   157  			So(*imageSummary.Vulnerabilities.Count, ShouldEqual, 0)
   158  			So(*imageSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "")
   159  			So(graphql.GetErrors(ctx).Error(), ShouldContainSubstring, "unable to run vulnerability scan on tag")
   160  		})
   161  
   162  		Convey("Add CVE Summary to RepoSummary", func() {
   163  			var repoSummary *gql_generated.RepoSummary
   164  			So(repoSummary, ShouldBeNil)
   165  
   166  			updateRepoSummaryVulnerabilities(ctx,
   167  				repoSummary,
   168  				SkipQGLField{
   169  					Vulnerabilities: false,
   170  				},
   171  				mocks.CveInfoMock{
   172  					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
   173  					) (cvemodel.ImageCVESummary, error) {
   174  						return cvemodel.ImageCVESummary{
   175  							Count:         30,
   176  							UnknownCount:  1,
   177  							LowCount:      2,
   178  							MediumCount:   3,
   179  							HighCount:     10,
   180  							CriticalCount: 14,
   181  							MaxSeverity:   "HIGH",
   182  						}, nil
   183  					},
   184  				},
   185  			)
   186  
   187  			So(repoSummary, ShouldBeNil)
   188  			So(graphql.GetErrors(ctx), ShouldBeNil)
   189  
   190  			imageSummary, _, err := ImageManifest2ImageSummary(ctx, GetFullImageMeta("0.1.0", repoMetaList[0],
   191  				imageMeta[image.DigestStr()]))
   192  			So(err, ShouldBeNil)
   193  
   194  			So(imageSummary, ShouldNotBeNil)
   195  
   196  			repoSummary = &gql_generated.RepoSummary{}
   197  			repoSummary.NewestImage = imageSummary
   198  
   199  			So(repoSummary.NewestImage.Vulnerabilities, ShouldBeNil)
   200  
   201  			updateImageSummaryVulnerabilities(ctx,
   202  				imageSummary,
   203  				SkipQGLField{
   204  					Vulnerabilities: false,
   205  				},
   206  				mocks.CveInfoMock{
   207  					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
   208  					) (cvemodel.ImageCVESummary, error) {
   209  						return cvemodel.ImageCVESummary{
   210  							Count:         30,
   211  							UnknownCount:  1,
   212  							LowCount:      2,
   213  							MediumCount:   3,
   214  							HighCount:     10,
   215  							CriticalCount: 14,
   216  							MaxSeverity:   "HIGH",
   217  						}, nil
   218  					},
   219  				},
   220  			)
   221  
   222  			So(repoSummary.NewestImage.Vulnerabilities, ShouldNotBeNil)
   223  			So(*repoSummary.NewestImage.Vulnerabilities.Count, ShouldEqual, 30)
   224  			So(*repoSummary.NewestImage.Vulnerabilities.UnknownCount, ShouldEqual, 1)
   225  			So(*repoSummary.NewestImage.Vulnerabilities.LowCount, ShouldEqual, 2)
   226  			So(*repoSummary.NewestImage.Vulnerabilities.MediumCount, ShouldEqual, 3)
   227  			So(*repoSummary.NewestImage.Vulnerabilities.HighCount, ShouldEqual, 10)
   228  			So(*repoSummary.NewestImage.Vulnerabilities.CriticalCount, ShouldEqual, 14)
   229  			So(*repoSummary.NewestImage.Vulnerabilities.MaxSeverity, ShouldEqual, "HIGH")
   230  			So(graphql.GetErrors(ctx), ShouldBeNil)
   231  		})
   232  
   233  		Convey("Add CVE Summary to ManifestSummary", func() {
   234  			var manifestSummary *gql_generated.ManifestSummary
   235  
   236  			So(manifestSummary, ShouldBeNil)
   237  
   238  			updateManifestSummaryVulnerabilities(ctx,
   239  				manifestSummary,
   240  				"repo1",
   241  				SkipQGLField{
   242  					Vulnerabilities: false,
   243  				},
   244  				mocks.CveInfoMock{
   245  					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
   246  					) (cvemodel.ImageCVESummary, error) {
   247  						return cvemodel.ImageCVESummary{
   248  							Count:       1,
   249  							MaxSeverity: "HIGH",
   250  						}, nil
   251  					},
   252  				},
   253  			)
   254  
   255  			So(manifestSummary, ShouldBeNil)
   256  			So(graphql.GetErrors(ctx), ShouldBeNil)
   257  
   258  			imageSummary, _, err := ImageManifest2ImageSummary(ctx, GetFullImageMeta("0.1.0", repoMetaList[0],
   259  				imageMeta[image.DigestStr()]))
   260  			So(err, ShouldBeNil)
   261  			manifestSummary = imageSummary.Manifests[0]
   262  
   263  			updateManifestSummaryVulnerabilities(ctx,
   264  				manifestSummary,
   265  				"repo1",
   266  				SkipQGLField{
   267  					Vulnerabilities: true,
   268  				},
   269  				mocks.CveInfoMock{},
   270  			)
   271  
   272  			So(manifestSummary, ShouldNotBeNil)
   273  			So(manifestSummary.Vulnerabilities, ShouldNotBeNil)
   274  			So(*manifestSummary.Vulnerabilities.Count, ShouldEqual, 0)
   275  			So(*manifestSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "")
   276  
   277  			manifestSummary.Vulnerabilities = nil
   278  
   279  			updateManifestSummaryVulnerabilities(ctx,
   280  				manifestSummary,
   281  				"repo1",
   282  				SkipQGLField{
   283  					Vulnerabilities: false,
   284  				},
   285  				mocks.CveInfoMock{
   286  					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
   287  					) (cvemodel.ImageCVESummary, error) {
   288  						return cvemodel.ImageCVESummary{
   289  							Count:         30,
   290  							UnknownCount:  1,
   291  							LowCount:      2,
   292  							MediumCount:   3,
   293  							HighCount:     10,
   294  							CriticalCount: 14,
   295  							MaxSeverity:   "HIGH",
   296  						}, nil
   297  					},
   298  				},
   299  			)
   300  
   301  			So(manifestSummary.Vulnerabilities, ShouldNotBeNil)
   302  			So(*manifestSummary.Vulnerabilities.Count, ShouldEqual, 30)
   303  			So(*manifestSummary.Vulnerabilities.UnknownCount, ShouldEqual, 1)
   304  			So(*manifestSummary.Vulnerabilities.LowCount, ShouldEqual, 2)
   305  			So(*manifestSummary.Vulnerabilities.MediumCount, ShouldEqual, 3)
   306  			So(*manifestSummary.Vulnerabilities.HighCount, ShouldEqual, 10)
   307  			So(*manifestSummary.Vulnerabilities.CriticalCount, ShouldEqual, 14)
   308  			So(*manifestSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "HIGH")
   309  
   310  			manifestSummary.Vulnerabilities = nil
   311  
   312  			updateManifestSummaryVulnerabilities(ctx,
   313  				manifestSummary,
   314  				"repo1",
   315  				SkipQGLField{
   316  					Vulnerabilities: false,
   317  				},
   318  				mocks.CveInfoMock{
   319  					GetCVESummaryForImageMediaFn: func(ctx context.Context, repo string, digest, mediaType string,
   320  					) (cvemodel.ImageCVESummary, error) {
   321  						return cvemodel.ImageCVESummary{}, ErrTestError
   322  					},
   323  				},
   324  			)
   325  
   326  			So(manifestSummary.Vulnerabilities, ShouldNotBeNil)
   327  			So(*manifestSummary.Vulnerabilities.Count, ShouldEqual, 0)
   328  			So(*manifestSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "")
   329  			So(graphql.GetErrors(ctx).Error(), ShouldContainSubstring, "unable to run vulnerability scan in repo")
   330  		})
   331  	})
   332  }