refactor: remove pkg/extensions/search/common and move the code to the appropriate packages (#1358)

Signed-off-by: Nicol Draghici <idraghic@cisco.com>
This commit is contained in:
Nicol
2023-04-18 21:07:47 +03:00
committed by GitHub
parent e63faa8898
commit 0586c6227e
25 changed files with 561 additions and 595 deletions
-317
View File
@@ -1,317 +0,0 @@
package common
import (
"fmt"
"sort"
"strings"
"time"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"zotregistry.io/zot/pkg/storage"
)
const (
// See https://github.com/opencontainers/image-spec/blob/main/annotations.md#back-compatibility-with-label-schema
AnnotationLabels = "org.label-schema.labels"
LabelAnnotationCreated = "org.label-schema.build-date"
LabelAnnotationVendor = "org.label-schema.vendor"
LabelAnnotationDescription = "org.label-schema.description"
LabelAnnotationLicenses = "org.label-schema.license"
LabelAnnotationTitle = "org.label-schema.name"
LabelAnnotationDocumentation = "org.label-schema.usage"
LabelAnnotationSource = "org.label-schema.vcs-url"
)
type Descriptor struct {
Digest godigest.Digest
MediaType string
}
type TagInfo struct {
Name string
Descriptor Descriptor
Timestamp time.Time
}
func GetRootDir(image string, storeController storage.StoreController) string {
var rootDir string
prefixName := GetRoutePrefix(image)
subStore := storeController.SubStore
if subStore != nil {
imgStore, ok := storeController.SubStore[prefixName]
if ok {
rootDir = imgStore.RootDir()
} else {
rootDir = storeController.DefaultStore.RootDir()
}
} else {
rootDir = storeController.DefaultStore.RootDir()
}
return rootDir
}
func GetRepo(image string) string {
if strings.Contains(image, ":") {
splitString := strings.SplitN(image, ":", 2) //nolint:gomnd
if len(splitString) != 2 { //nolint:gomnd
return image
}
return splitString[0]
}
return image
}
func GetImageDirAndTag(imageName string) (string, string) {
var imageDir string
var imageTag string
if strings.Contains(imageName, ":") {
imageDir, imageTag, _ = strings.Cut(imageName, ":")
} else {
imageDir = imageName
}
return imageDir, imageTag
}
func GetImageDirAndDigest(imageName string) (string, string) {
var imageDir string
var imageDigest string
if strings.Contains(imageName, "@") {
imageDir, imageDigest, _ = strings.Cut(imageName, "@")
} else {
imageDir = imageName
}
return imageDir, imageDigest
}
// GetImageDirAndReference returns the repo, digest and isTag.
func GetImageDirAndReference(imageName string) (string, string, bool) {
if strings.Contains(imageName, "@") {
repo, digest := GetImageDirAndDigest(imageName)
return repo, digest, false
}
repo, tag := GetImageDirAndTag(imageName)
return repo, tag, true
}
// GetImageLastUpdated This method will return last updated timestamp.
// The Created timestamp is used, but if it is missing, look at the
// history field and, if provided, return the timestamp of last entry in history.
func GetImageLastUpdated(imageInfo ispec.Image) time.Time {
timeStamp := imageInfo.Created
if timeStamp != nil && !timeStamp.IsZero() {
return *timeStamp
}
if len(imageInfo.History) > 0 {
timeStamp = imageInfo.History[len(imageInfo.History)-1].Created
}
if timeStamp == nil {
timeStamp = &time.Time{}
}
return *timeStamp
}
func GetFixedTags(allTags, vulnerableTags []TagInfo) []TagInfo {
sort.Slice(allTags, func(i, j int) bool {
return allTags[i].Timestamp.Before(allTags[j].Timestamp)
})
earliestVulnerable := vulnerableTags[0]
vulnerableTagMap := make(map[string]TagInfo, len(vulnerableTags))
for _, tag := range vulnerableTags {
vulnerableTagMap[tag.Name] = tag
if tag.Timestamp.Before(earliestVulnerable.Timestamp) {
earliestVulnerable = tag
}
}
var fixedTags []TagInfo
// There are some downsides to this logic
// We assume there can't be multiple "branches" of the same
// image built at different times containing different fixes
// There may be older images which have a fix or
// newer images which don't
for _, tag := range allTags {
if tag.Timestamp.Before(earliestVulnerable.Timestamp) {
// The vulnerability did not exist at the time this
// image was built
continue
}
// If the image is old enough for the vulnerability to
// exist, but it was not detected, it means it contains
// the fix
if _, ok := vulnerableTagMap[tag.Name]; !ok {
fixedTags = append(fixedTags, tag)
}
}
return fixedTags
}
func GetLatestTag(allTags []TagInfo) TagInfo {
sort.Slice(allTags, func(i, j int) bool {
return allTags[i].Timestamp.Before(allTags[j].Timestamp)
})
return allTags[len(allTags)-1]
}
func GetRoutePrefix(name string) string {
names := strings.SplitN(name, "/", 2) //nolint:gomnd
if len(names) != 2 { //nolint:gomnd
// it means route is of global storage e.g "centos:latest"
if len(names) == 1 {
return "/"
}
}
return fmt.Sprintf("/%s", names[0])
}
type ImageAnnotations struct {
Description string
Licenses string
Title string
Documentation string
Source string
Labels string
Vendor string
Authors string
}
/*
OCI annotation/label with backwards compatibility
arg can be either lables or annotations
https://github.com/opencontainers/image-spec/blob/main/annotations.md.
*/
func GetAnnotationValue(annotations map[string]string, annotationKey, labelKey string) string {
value, ok := annotations[annotationKey]
if !ok || value == "" {
value, ok = annotations[labelKey]
if !ok {
value = ""
}
}
return value
}
func GetDescription(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationDescription, LabelAnnotationDescription)
}
func GetLicenses(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationLicenses, LabelAnnotationLicenses)
}
func GetVendor(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationVendor, LabelAnnotationVendor)
}
func GetAuthors(annotations map[string]string) string {
authors := annotations[ispec.AnnotationAuthors]
return authors
}
func GetTitle(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationTitle, LabelAnnotationTitle)
}
func GetDocumentation(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationDocumentation, LabelAnnotationDocumentation)
}
func GetSource(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationSource, LabelAnnotationSource)
}
func GetCategories(labels map[string]string) string {
categories := labels[AnnotationLabels]
return categories
}
func GetAnnotations(annotations, labels map[string]string) ImageAnnotations {
description := GetDescription(annotations)
if description == "" {
description = GetDescription(labels)
}
title := GetTitle(annotations)
if title == "" {
title = GetTitle(labels)
}
documentation := GetDocumentation(annotations)
if documentation == "" {
documentation = GetDocumentation(labels)
}
source := GetSource(annotations)
if source == "" {
source = GetSource(labels)
}
licenses := GetLicenses(annotations)
if licenses == "" {
licenses = GetLicenses(labels)
}
categories := GetCategories(annotations)
if categories == "" {
categories = GetCategories(labels)
}
vendor := GetVendor(annotations)
if vendor == "" {
vendor = GetVendor(labels)
}
authors := GetAuthors(annotations)
if authors == "" {
authors = GetAuthors(labels)
}
return ImageAnnotations{
Description: description,
Title: title,
Documentation: documentation,
Source: source,
Licenses: licenses,
Labels: categories,
Vendor: vendor,
Authors: authors,
}
}
func ReferenceIsDigest(reference string) bool {
_, err := godigest.Parse(reference)
return err == nil
}
-95
View File
@@ -1,95 +0,0 @@
package common
import (
"time"
)
type RepoInfo struct {
Summary RepoSummary
ImageSummaries []ImageSummary `json:"images"`
}
type RepoSummary struct {
Name string `json:"name"`
LastUpdated time.Time `json:"lastUpdated"`
Size string `json:"size"`
Platforms []Platform `json:"platforms"`
Vendors []string `json:"vendors"`
NewestImage ImageSummary `json:"newestImage"`
}
type ImageSummary struct {
RepoName string `json:"repoName"`
Tag string `json:"tag"`
Digest string `json:"digest"`
MediaType string `json:"mediaType"`
Manifests []ManifestSummary `json:"manifests"`
Size string `json:"size"`
DownloadCount int `json:"downloadCount"`
LastUpdated time.Time `json:"lastUpdated"`
Description string `json:"description"`
IsSigned bool `json:"isSigned"`
Licenses string `json:"licenses"`
Labels string `json:"labels"`
Title string `json:"title"`
Source string `json:"source"`
Documentation string `json:"documentation"`
Authors string `json:"authors"`
Vendor string `json:"vendor"`
Vulnerabilities ImageVulnerabilitySummary `json:"vulnerabilities"`
Referrers []Referrer `json:"referrers"`
}
type ManifestSummary struct {
Digest string `json:"digest"`
ConfigDigest string `json:"configDigest"`
LastUpdated time.Time `json:"lastUpdated"`
Size string `json:"size"`
Platform Platform `json:"platform"`
DownloadCount int `json:"downloadCount"`
Layers []LayerSummary `json:"layers"`
History []LayerHistory `json:"history"`
Vulnerabilities ImageVulnerabilitySummary `json:"vulnerabilities"`
}
type Platform struct {
Os string `json:"os"`
Arch string `json:"arch"`
}
type ImageVulnerabilitySummary struct {
MaxSeverity string `json:"maxSeverity"`
Count int `json:"count"`
}
type LayerSummary struct {
Size string `json:"size"`
Digest string `json:"digest"`
Score int `json:"score"`
}
type LayerHistory struct {
Layer LayerSummary `json:"layer"`
HistoryDescription HistoryDescription `json:"historyDescription"`
}
type HistoryDescription struct {
Created time.Time `json:"created"`
CreatedBy string `json:"createdBy"`
Author string `json:"author"`
Comment string `json:"comment"`
EmptyLayer bool `json:"emptyLayer"`
}
type Referrer struct {
MediaType string `json:"mediatype"`
ArtifactType string `json:"artifacttype"`
Size int `json:"size"`
Digest string `json:"digest"`
Annotations []Annotation `json:"annotations"`
}
type Annotation struct {
Key string `json:"key"`
Value string `json:"value"`
}
@@ -0,0 +1,135 @@
package convert
import (
ispec "github.com/opencontainers/image-spec/specs-go/v1"
)
const (
// See https://github.com/opencontainers/image-spec/blob/main/annotations.md#back-compatibility-with-label-schema
AnnotationLabels = "org.label-schema.labels"
LabelAnnotationCreated = "org.label-schema.build-date"
LabelAnnotationVendor = "org.label-schema.vendor"
LabelAnnotationDescription = "org.label-schema.description"
LabelAnnotationLicenses = "org.label-schema.license"
LabelAnnotationTitle = "org.label-schema.name"
LabelAnnotationDocumentation = "org.label-schema.usage"
LabelAnnotationSource = "org.label-schema.vcs-url"
)
type ImageAnnotations struct {
Description string
Licenses string
Title string
Documentation string
Source string
Labels string
Vendor string
Authors string
}
/*
OCI annotation/label with backwards compatibility
arg can be either lables or annotations
https://github.com/opencontainers/image-spec/blob/main/annotations.md.
*/
func GetAnnotationValue(annotations map[string]string, annotationKey, labelKey string) string {
value, ok := annotations[annotationKey]
if !ok || value == "" {
value, ok = annotations[labelKey]
if !ok {
value = ""
}
}
return value
}
func GetDescription(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationDescription, LabelAnnotationDescription)
}
func GetLicenses(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationLicenses, LabelAnnotationLicenses)
}
func GetVendor(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationVendor, LabelAnnotationVendor)
}
func GetAuthors(annotations map[string]string) string {
authors := annotations[ispec.AnnotationAuthors]
return authors
}
func GetTitle(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationTitle, LabelAnnotationTitle)
}
func GetDocumentation(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationDocumentation, LabelAnnotationDocumentation)
}
func GetSource(annotations map[string]string) string {
return GetAnnotationValue(annotations, ispec.AnnotationSource, LabelAnnotationSource)
}
func GetCategories(labels map[string]string) string {
categories := labels[AnnotationLabels]
return categories
}
func GetAnnotations(annotations, labels map[string]string) ImageAnnotations {
description := GetDescription(annotations)
if description == "" {
description = GetDescription(labels)
}
title := GetTitle(annotations)
if title == "" {
title = GetTitle(labels)
}
documentation := GetDocumentation(annotations)
if documentation == "" {
documentation = GetDocumentation(labels)
}
source := GetSource(annotations)
if source == "" {
source = GetSource(labels)
}
licenses := GetLicenses(annotations)
if licenses == "" {
licenses = GetLicenses(labels)
}
categories := GetCategories(annotations)
if categories == "" {
categories = GetCategories(labels)
}
vendor := GetVendor(annotations)
if vendor == "" {
vendor = GetVendor(labels)
}
authors := GetAuthors(annotations)
if authors == "" {
authors = GetAuthors(labels)
}
return ImageAnnotations{
Description: description,
Title: title,
Documentation: documentation,
Source: source,
Licenses: licenses,
Labels: categories,
Vendor: vendor,
Authors: authors,
}
}
@@ -333,3 +333,55 @@ func TestUpdateLastUpdatedTimestam(t *testing.T) {
So(*img.LastUpdated, ShouldResemble, after)
})
}
func TestLabels(t *testing.T) {
Convey("Test labels", t, func() {
// Test various labels
labels := make(map[string]string)
desc := convert.GetDescription(labels)
So(desc, ShouldEqual, "")
license := convert.GetLicenses(labels)
So(license, ShouldEqual, "")
vendor := convert.GetVendor(labels)
So(vendor, ShouldEqual, "")
categories := convert.GetCategories(labels)
So(categories, ShouldEqual, "")
labels[ispec.AnnotationVendor] = "zot"
labels[ispec.AnnotationDescription] = "zot-desc"
labels[ispec.AnnotationLicenses] = "zot-license"
labels[convert.AnnotationLabels] = "zot-labels"
desc = convert.GetDescription(labels)
So(desc, ShouldEqual, "zot-desc")
license = convert.GetLicenses(labels)
So(license, ShouldEqual, "zot-license")
vendor = convert.GetVendor(labels)
So(vendor, ShouldEqual, "zot")
categories = convert.GetCategories(labels)
So(categories, ShouldEqual, "zot-labels")
labels = make(map[string]string)
// Use diff key
labels[convert.LabelAnnotationVendor] = "zot-vendor"
labels[convert.LabelAnnotationDescription] = "zot-label-desc"
labels[ispec.AnnotationLicenses] = "zot-label-license"
desc = convert.GetDescription(labels)
So(desc, ShouldEqual, "zot-label-desc")
license = convert.GetLicenses(labels)
So(license, ShouldEqual, "zot-label-license")
vendor = convert.GetVendor(labels)
So(vendor, ShouldEqual, "zot-vendor")
})
}
+3 -3
View File
@@ -14,7 +14,7 @@ import (
"github.com/vektah/gqlparser/v2/gqlerror"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/extensions/search/common"
"zotregistry.io/zot/pkg/common"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
@@ -240,7 +240,7 @@ func ImageIndex2ImageSummary(ctx context.Context, repo, tag string, indexDigest
indexSize = strconv.FormatInt(totalIndexSize, 10)
annotations := common.GetAnnotations(indexContent.Annotations, map[string]string{})
annotations := GetAnnotations(indexContent.Annotations, map[string]string{})
indexSummary := gql_generated.ImageSummary{
RepoName: &repo,
@@ -327,7 +327,7 @@ func ImageManifest2ImageSummary(ctx context.Context, repo, tag string, digest go
manifestContent.Layers)
imageSize := strconv.FormatInt(size, 10)
annotations := common.GetAnnotations(manifestContent.Annotations, configContent.Config.Labels)
annotations := GetAnnotations(manifestContent.Annotations, configContent.Config.Labels)
authors := annotations.Authors
if authors == "" {
+64 -17
View File
@@ -3,13 +3,14 @@ package cveinfo
import (
"encoding/json"
"fmt"
"sort"
"strings"
godigest "github.com/opencontainers/go-digest"
ispec "github.com/opencontainers/image-spec/specs-go/v1"
"zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/extensions/search/common"
"zotregistry.io/zot/pkg/common"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/extensions/search/cve/trivy"
"zotregistry.io/zot/pkg/log"
@@ -18,8 +19,8 @@ import (
)
type CveInfo interface {
GetImageListForCVE(repo, cveID string) ([]common.TagInfo, error)
GetImageListWithCVEFixed(repo, cveID string) ([]common.TagInfo, error)
GetImageListForCVE(repo, cveID string) ([]cvemodel.TagInfo, error)
GetImageListWithCVEFixed(repo, cveID string) ([]cvemodel.TagInfo, error)
GetCVEListForImage(repo, tag string, searchedCVE string, pageinput PageInput) ([]cvemodel.CVE, PageInfo, error)
GetCVESummaryForImage(repo, tag string) (ImageCVESummary, error)
CompareSeverities(severity1, severity2 string) int
@@ -56,8 +57,8 @@ func NewCVEInfo(storeController storage.StoreController, repoDB repodb.RepoDB,
}
}
func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]common.TagInfo, error) {
imgList := make([]common.TagInfo, 0)
func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]cvemodel.TagInfo, error) {
imgList := make([]cvemodel.TagInfo, 0)
repoMeta, err := cveinfo.RepoDB.GetRepoMeta(repo)
if err != nil {
@@ -89,9 +90,9 @@ func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]common.TagI
}
if _, hasCVE := cveMap[cveID]; hasCVE {
imgList = append(imgList, common.TagInfo{
imgList = append(imgList, cvemodel.TagInfo{
Name: tag,
Descriptor: common.Descriptor{
Descriptor: cvemodel.Descriptor{
Digest: manifestDigest,
MediaType: descriptor.MediaType,
},
@@ -105,17 +106,17 @@ func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]common.TagI
return imgList, nil
}
func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]common.TagInfo, error) {
func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]cvemodel.TagInfo, error) {
repoMeta, err := cveinfo.RepoDB.GetRepoMeta(repo)
if err != nil {
cveinfo.Log.Error().Err(err).Str("repo", repo).Str("cve-id", cveID).
Msg("unable to get list of tags from repo")
return []common.TagInfo{}, err
return []cvemodel.TagInfo{}, err
}
vulnerableTags := make([]common.TagInfo, 0)
allTags := make([]common.TagInfo, 0)
vulnerableTags := make([]cvemodel.TagInfo, 0)
allTags := make([]cvemodel.TagInfo, 0)
var hasCVE bool
@@ -150,10 +151,10 @@ func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]commo
continue
}
tagInfo := common.TagInfo{
tagInfo := cvemodel.TagInfo{
Name: tag,
Timestamp: common.GetImageLastUpdated(configContent),
Descriptor: common.Descriptor{Digest: manifestDigest, MediaType: descriptor.MediaType},
Descriptor: cvemodel.Descriptor{Digest: manifestDigest, MediaType: descriptor.MediaType},
}
allTags = append(allTags, tagInfo)
@@ -196,16 +197,16 @@ func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]commo
default:
cveinfo.Log.Error().Msgf("media type not supported '%s'", descriptor.MediaType)
return []common.TagInfo{},
return []cvemodel.TagInfo{},
fmt.Errorf("media type '%s' is not supported: %w", descriptor.MediaType, errors.ErrNotImplemented)
}
}
var fixedTags []common.TagInfo
var fixedTags []cvemodel.TagInfo
if len(vulnerableTags) != 0 {
cveinfo.Log.Info().Str("repo", repo).Str("cve-id", cveID).Msgf("Vulnerable tags: %v", vulnerableTags)
fixedTags = common.GetFixedTags(allTags, vulnerableTags)
fixedTags = GetFixedTags(allTags, vulnerableTags)
cveinfo.Log.Info().Str("repo", repo).Str("cve-id", cveID).Msgf("Fixed tags: %v", fixedTags)
} else {
cveinfo.Log.Info().Str("repo", repo).Str("cve-id", cveID).
@@ -297,10 +298,16 @@ func (cveinfo BaseCveInfo) GetCVESummaryForImage(repo, tag string,
return imageCVESummary, nil
}
func referenceIsDigest(reference string) bool {
_, err := godigest.Parse(reference)
return err == nil
}
func getImageString(repo, reference string) string {
image := repo + ":" + reference
if common.ReferenceIsDigest(reference) {
if referenceIsDigest(reference) {
image = repo + "@" + reference
}
@@ -314,3 +321,43 @@ func (cveinfo BaseCveInfo) UpdateDB() error {
func (cveinfo BaseCveInfo) CompareSeverities(severity1, severity2 string) int {
return cveinfo.Scanner.CompareSeverities(severity1, severity2)
}
func GetFixedTags(allTags, vulnerableTags []cvemodel.TagInfo) []cvemodel.TagInfo {
sort.Slice(allTags, func(i, j int) bool {
return allTags[i].Timestamp.Before(allTags[j].Timestamp)
})
earliestVulnerable := vulnerableTags[0]
vulnerableTagMap := make(map[string]cvemodel.TagInfo, len(vulnerableTags))
for _, tag := range vulnerableTags {
vulnerableTagMap[tag.Name] = tag
if tag.Timestamp.Before(earliestVulnerable.Timestamp) {
earliestVulnerable = tag
}
}
var fixedTags []cvemodel.TagInfo
// There are some downsides to this logic
// We assume there can't be multiple "branches" of the same
// image built at different times containing different fixes
// There may be older images which have a fix or
// newer images which don't
for _, tag := range allTags {
if tag.Timestamp.Before(earliestVulnerable.Timestamp) {
// The vulnerability did not exist at the time this
// image was built
continue
}
// If the image is old enough for the vulnerability to
// exist, but it was not detected, it means it contains
// the fix
if _, ok := vulnerableTagMap[tag.Name]; !ok {
fixedTags = append(fixedTags, tag)
}
}
return fixedTags
}
+60
View File
@@ -1440,3 +1440,63 @@ func TestCVEStruct(t *testing.T) {
So(err, ShouldBeNil)
})
}
func getTags() ([]cvemodel.TagInfo, []cvemodel.TagInfo) {
tags := make([]cvemodel.TagInfo, 0)
firstTag := cvemodel.TagInfo{
Name: "1.0.0",
Descriptor: cvemodel.Descriptor{
Digest: "sha256:eca04f027f414362596f2632746d8a178362170b9ac9af772011fedcc3877ebb",
MediaType: ispec.MediaTypeImageManifest,
},
Timestamp: time.Now(),
}
secondTag := cvemodel.TagInfo{
Name: "1.0.1",
Descriptor: cvemodel.Descriptor{
Digest: "sha256:eca04f027f414362596f2632746d8a179362170b9ac9af772011fedcc3877ebb",
MediaType: ispec.MediaTypeImageManifest,
},
Timestamp: time.Now(),
}
thirdTag := cvemodel.TagInfo{
Name: "1.0.2",
Descriptor: cvemodel.Descriptor{
Digest: "sha256:eca04f027f414362596f2632746d8a170362170b9ac9af772011fedcc3877ebb",
MediaType: ispec.MediaTypeImageManifest,
},
Timestamp: time.Now(),
}
fourthTag := cvemodel.TagInfo{
Name: "1.0.3",
Descriptor: cvemodel.Descriptor{
Digest: "sha256:eca04f027f414362596f2632746d8a171362170b9ac9af772011fedcc3877ebb",
MediaType: ispec.MediaTypeImageManifest,
},
Timestamp: time.Now(),
}
tags = append(tags, firstTag, secondTag, thirdTag, fourthTag)
vulnerableTags := make([]cvemodel.TagInfo, 0)
vulnerableTags = append(vulnerableTags, secondTag)
return tags, vulnerableTags
}
func TestFixedTags(t *testing.T) {
Convey("Test fixed tags", t, func() {
allTags, vulnerableTags := getTags()
fixedTags := cveinfo.GetFixedTags(allTags, vulnerableTags)
So(len(fixedTags), ShouldEqual, 2)
fixedTags = cveinfo.GetFixedTags(allTags, append(vulnerableTags, cvemodel.TagInfo{
Name: "taginfo",
Descriptor: cvemodel.Descriptor{},
Timestamp: time.Date(2000, time.July, 20, 10, 10, 10, 10, time.UTC),
}))
So(len(fixedTags), ShouldEqual, 3)
})
}
+17
View File
@@ -1,5 +1,11 @@
package model
import (
"time"
godigest "github.com/opencontainers/go-digest"
)
//nolint:tagliatelle // graphQL schema
type CVE struct {
ID string `json:"Id"`
@@ -35,3 +41,14 @@ func SeverityValue(severity string) int {
return sevMap[severity]
}
type Descriptor struct {
Digest godigest.Digest
MediaType string
}
type TagInfo struct {
Name string
Descriptor Descriptor
Timestamp time.Time
}
+1 -2
View File
@@ -17,7 +17,6 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/extensions/search/common"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/repodb"
@@ -122,7 +121,7 @@ func NewScanner(storeController storage.StoreController,
func (scanner Scanner) getTrivyOptions(image string) flag.Options {
// Split image to get route prefix
prefixName := common.GetRoutePrefix(image)
prefixName := storage.GetRoutePrefix(image)
var opts flag.Options
@@ -15,8 +15,8 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/extensions/monitoring"
"zotregistry.io/zot/pkg/extensions/search/common"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/bolt"
"zotregistry.io/zot/pkg/meta/repodb"
+2 -7
View File
@@ -30,7 +30,7 @@ type ImgResponseForDigest struct {
//nolint:tagliatelle // graphQL schema
type ImgListForDigest struct {
PaginatedImagesResult `json:"ImageListForDigest"`
PaginatedImagesResultForDigest `json:"ImageListForDigest"`
}
//nolint:tagliatelle // graphQL schema
@@ -42,12 +42,7 @@ type ImgInfo struct {
Size string `json:"Size"`
}
type ErrorGQL struct {
Message string `json:"message"`
Path []string `json:"path"`
}
type PaginatedImagesResult struct {
type PaginatedImagesResultForDigest struct {
Results []ImgInfo `json:"results"`
Page repodb.PageInfo `json:"page"`
}
+4 -3
View File
@@ -18,9 +18,10 @@ import (
"github.com/vektah/gqlparser/v2/gqlerror"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/extensions/search/common"
"zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/extensions/search/convert"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/meta/repodb"
@@ -357,7 +358,7 @@ func getCVEListForImage(
}, nil
}
func FilterByTagInfo(tagsInfo []common.TagInfo) repodb.FilterFunc {
func FilterByTagInfo(tagsInfo []cvemodel.TagInfo) repodb.FilterFunc {
return func(repoMeta repodb.RepoMetadata, manifestMeta repodb.ManifestMetadata) bool {
manifestDigest := godigest.FromBytes(manifestMeta.ManifestBlob).String()
@@ -391,7 +392,7 @@ func getImageListForCVE(
return &gql_generated.PaginatedImagesResult{}, err
}
affectedImages := []common.TagInfo{}
affectedImages := []cvemodel.TagInfo{}
for _, repoMeta := range reposMeta {
repo := repoMeta.Name
+1 -1
View File
@@ -14,7 +14,7 @@ import (
ispec "github.com/opencontainers/image-spec/specs-go/v1"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/pkg/extensions/search/common"
"zotregistry.io/zot/pkg/common"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"github.com/vektah/gqlparser/v2/gqlerror"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/extensions/search/common"
"zotregistry.io/zot/pkg/common"
"zotregistry.io/zot/pkg/extensions/search/gql_generated"
)
@@ -1,7 +1,7 @@
//go:build search
// +build search
package common_test
package search_test
import (
"context"
@@ -31,9 +31,9 @@ import (
"zotregistry.io/zot/pkg/api"
"zotregistry.io/zot/pkg/api/config"
"zotregistry.io/zot/pkg/api/constants"
"zotregistry.io/zot/pkg/common"
extconf "zotregistry.io/zot/pkg/extensions/config"
"zotregistry.io/zot/pkg/extensions/monitoring"
"zotregistry.io/zot/pkg/extensions/search/common"
cveinfo "zotregistry.io/zot/pkg/extensions/search/cve"
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
"zotregistry.io/zot/pkg/log"
@@ -42,6 +42,7 @@ import (
"zotregistry.io/zot/pkg/storage/local"
. "zotregistry.io/zot/pkg/test"
"zotregistry.io/zot/pkg/test/mocks"
ocilayout "zotregistry.io/zot/pkg/test/oci-layout"
)
const (
@@ -146,50 +147,6 @@ type ImageSummaryResult struct {
Errors []ErrorGQL `json:"errors"`
}
func getTags() ([]common.TagInfo, []common.TagInfo) {
tags := make([]common.TagInfo, 0)
firstTag := common.TagInfo{
Name: "1.0.0",
Descriptor: common.Descriptor{
Digest: "sha256:eca04f027f414362596f2632746d8a178362170b9ac9af772011fedcc3877ebb",
MediaType: ispec.MediaTypeImageManifest,
},
Timestamp: time.Now(),
}
secondTag := common.TagInfo{
Name: "1.0.1",
Descriptor: common.Descriptor{
Digest: "sha256:eca04f027f414362596f2632746d8a179362170b9ac9af772011fedcc3877ebb",
MediaType: ispec.MediaTypeImageManifest,
},
Timestamp: time.Now(),
}
thirdTag := common.TagInfo{
Name: "1.0.2",
Descriptor: common.Descriptor{
Digest: "sha256:eca04f027f414362596f2632746d8a170362170b9ac9af772011fedcc3877ebb",
MediaType: ispec.MediaTypeImageManifest,
},
Timestamp: time.Now(),
}
fourthTag := common.TagInfo{
Name: "1.0.3",
Descriptor: common.Descriptor{
Digest: "sha256:eca04f027f414362596f2632746d8a171362170b9ac9af772011fedcc3877ebb",
MediaType: ispec.MediaTypeImageManifest,
},
Timestamp: time.Now(),
}
tags = append(tags, firstTag, secondTag, thirdTag, fourthTag)
vulnerableTags := make([]common.TagInfo, 0)
vulnerableTags = append(vulnerableTags, secondTag)
return tags, vulnerableTags
}
func readFileAndSearchString(filePath string, stringToMatch string, timeout time.Duration) (bool, error) {
ctx, cancelFunc := context.WithTimeout(context.Background(), timeout)
defer cancelFunc()
@@ -1796,136 +1753,6 @@ func TestExpandedRepoInfo(t *testing.T) {
})
}
func TestUtilsMethod(t *testing.T) {
Convey("Test utils", t, func() {
// Test GetRepo method
repo := common.GetRepo("test")
So(repo, ShouldEqual, "test")
repo = common.GetRepo(":")
So(repo, ShouldEqual, "")
repo = common.GetRepo("")
So(repo, ShouldEqual, "")
repo = common.GetRepo("test:123")
So(repo, ShouldEqual, "test")
repo = common.GetRepo("a/test:123")
So(repo, ShouldEqual, "a/test")
repo = common.GetRepo("a/test:123:456")
So(repo, ShouldEqual, "a/test")
// Test various labels
labels := make(map[string]string)
desc := common.GetDescription(labels)
So(desc, ShouldEqual, "")
license := common.GetLicenses(labels)
So(license, ShouldEqual, "")
vendor := common.GetVendor(labels)
So(vendor, ShouldEqual, "")
categories := common.GetCategories(labels)
So(categories, ShouldEqual, "")
labels[ispec.AnnotationVendor] = "zot"
labels[ispec.AnnotationDescription] = "zot-desc"
labels[ispec.AnnotationLicenses] = "zot-license"
labels[common.AnnotationLabels] = "zot-labels"
desc = common.GetDescription(labels)
So(desc, ShouldEqual, "zot-desc")
license = common.GetLicenses(labels)
So(license, ShouldEqual, "zot-license")
vendor = common.GetVendor(labels)
So(vendor, ShouldEqual, "zot")
categories = common.GetCategories(labels)
So(categories, ShouldEqual, "zot-labels")
labels = make(map[string]string)
// Use diff key
labels[common.LabelAnnotationVendor] = "zot-vendor"
labels[common.LabelAnnotationDescription] = "zot-label-desc"
labels[ispec.AnnotationLicenses] = "zot-label-license"
desc = common.GetDescription(labels)
So(desc, ShouldEqual, "zot-label-desc")
license = common.GetLicenses(labels)
So(license, ShouldEqual, "zot-label-license")
vendor = common.GetVendor(labels)
So(vendor, ShouldEqual, "zot-vendor")
routePrefix := common.GetRoutePrefix("test:latest")
So(routePrefix, ShouldEqual, "/")
routePrefix = common.GetRoutePrefix("a/test:latest")
So(routePrefix, ShouldEqual, "/a")
routePrefix = common.GetRoutePrefix("a/b/test:latest")
So(routePrefix, ShouldEqual, "/a")
allTags, vulnerableTags := getTags()
latestTag := common.GetLatestTag(allTags)
So(latestTag.Name, ShouldEqual, "1.0.3")
fixedTags := common.GetFixedTags(allTags, vulnerableTags)
So(len(fixedTags), ShouldEqual, 2)
fixedTags = common.GetFixedTags(allTags, append(vulnerableTags, common.TagInfo{
Name: "taginfo",
Descriptor: common.Descriptor{},
Timestamp: time.Date(2000, time.July, 20, 10, 10, 10, 10, time.UTC),
}))
So(len(fixedTags), ShouldEqual, 3)
log := log.NewLogger("debug", "")
rootDir := t.TempDir()
subRootDir := t.TempDir()
conf := config.New()
conf.Extensions = &extconf.ExtensionConfig{}
conf.Extensions.Lint = &extconf.LintConfig{}
metrics := monitoring.NewMetricsServer(false, log)
defaultStore := local.NewImageStore(rootDir, false,
storage.DefaultGCDelay, false, false, log, metrics, nil, nil)
subStore := local.NewImageStore(subRootDir, false,
storage.DefaultGCDelay, false, false, log, metrics, nil, nil)
subStoreMap := make(map[string]storage.ImageStore)
subStoreMap["/b"] = subStore
storeController := storage.StoreController{DefaultStore: defaultStore, SubStore: subStoreMap}
dir := common.GetRootDir("a/zot-cve-test", storeController)
So(dir, ShouldEqual, rootDir)
dir = common.GetRootDir("b/zot-cve-test", storeController)
So(dir, ShouldEqual, subRootDir)
repo, digest := common.GetImageDirAndDigest("image")
So(repo, ShouldResemble, "image")
So(digest, ShouldResemble, "")
})
}
func TestDerivedImageList(t *testing.T) {
rootDir := t.TempDir()
@@ -2390,7 +2217,7 @@ func TestGetImageManifest(t *testing.T) {
storeController := storage.StoreController{
DefaultStore: mockImageStore,
}
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
olu := ocilayout.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
_, _, err := olu.GetImageManifest("nonexistent-repo", "latest")
So(err, ShouldNotBeNil)
@@ -2406,7 +2233,7 @@ func TestGetImageManifest(t *testing.T) {
storeController := storage.StoreController{
DefaultStore: mockImageStore,
}
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
olu := ocilayout.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
_, _, err := olu.GetImageManifest("test-repo", "latest") //nolint:goconst
So(err, ShouldNotBeNil)
@@ -3068,7 +2895,7 @@ func TestGetRepositories(t *testing.T) {
DefaultStore: mockImageStore,
SubStore: map[string]storage.ImageStore{"test": mockImageStore},
}
olu := NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
olu := ocilayout.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
repoList, err := olu.GetRepositories()
So(repoList, ShouldBeEmpty)
@@ -3078,7 +2905,7 @@ func TestGetRepositories(t *testing.T) {
DefaultStore: mocks.MockedImageStore{},
SubStore: map[string]storage.ImageStore{"test": mockImageStore},
}
olu = NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
olu = ocilayout.NewBaseOciLayoutUtils(storeController, log.NewLogger("debug", ""))
repoList, err = olu.GetRepositories()
So(repoList, ShouldBeEmpty)
@@ -3388,7 +3215,7 @@ func TestGlobalSearch(t *testing.T) {
)
So(err, ShouldBeNil)
olu := NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
olu := ocilayout.NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
// Initialize the objects containing the expected data
repos, err := olu.GetRepositories()
@@ -3717,7 +3544,7 @@ func TestGlobalSearch(t *testing.T) {
)
So(err, ShouldBeNil)
olu := NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
olu := ocilayout.NewBaseOciLayoutUtils(ctlr.StoreController, log.NewLogger("debug", ""))
// Initialize the objects containing the expected data
repos, err := olu.GetRepositories()