mirror of
https://github.com/project-zot/zot.git
synced 2024-12-23 22:27:35 -05:00
e0d808b196
Return this data as part of GlobalSearch and RepoListWithNewestImage query results. This commit also includes refactoring of the CVE scanning logic in order to better encapsulate trivy specific logic, remove CVE scanning logic from the graphql resolver. Signed-off-by: Andrei Aaron <andaaron@cisco.com>
227 lines
5.6 KiB
Go
227 lines
5.6 KiB
Go
package common
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
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"
|
|
LabelAnnotationTitle = "org.label-schema.name"
|
|
LabelAnnotationDocumentation = "org.label-schema.usage"
|
|
LabelAnnotationSource = "org.label-schema.vcs-url"
|
|
)
|
|
|
|
type TagInfo struct {
|
|
Name string
|
|
Digest string
|
|
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 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
|
|
}
|
|
|
|
/* 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 GetVendor(annotations map[string]string) string {
|
|
return GetAnnotationValue(annotations, ispec.AnnotationVendor, LabelAnnotationVendor)
|
|
}
|
|
|
|
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 GetLicenses(annotations map[string]string) string {
|
|
licenses := annotations[ispec.AnnotationLicenses]
|
|
|
|
return licenses
|
|
}
|
|
|
|
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(annotations)
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
return ImageAnnotations{
|
|
Description: description,
|
|
Title: title,
|
|
Documentation: documentation,
|
|
Source: source,
|
|
Licenses: licenses,
|
|
Labels: categories,
|
|
Vendor: vendor,
|
|
}
|
|
}
|