From 815366024baf0c81e4cd4da3c05d4ee8132c9307 Mon Sep 17 00:00:00 2001 From: Andrei Aaron Date: Tue, 11 Oct 2022 03:43:05 +0300 Subject: [PATCH] fix(lastUpdated): fix image lastUpdated timestamp logic (#863) The lastUpdated field was picked from the first entry in image history Now it is the created time of the image, or the last entry in image history, if created time is unavailable Signed-off-by: Andrei Aaron --- pkg/extensions/search/common/common.go | 21 +++++++++++++++++++ pkg/extensions/search/common/oci_layout.go | 24 ++-------------------- pkg/extensions/search/resolver.go | 19 ++++++----------- pkg/test/mocks/oci_mock.go | 11 ---------- 4 files changed, 29 insertions(+), 46 deletions(-) diff --git a/pkg/extensions/search/common/common.go b/pkg/extensions/search/common/common.go index a247ee52..96c808cb 100644 --- a/pkg/extensions/search/common/common.go +++ b/pkg/extensions/search/common/common.go @@ -75,6 +75,27 @@ func GetImageDirAndTag(imageName string) (string, string) { return imageDir, imageTag } +// 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) diff --git a/pkg/extensions/search/common/oci_layout.go b/pkg/extensions/search/common/oci_layout.go index 7ca726ed..3e513a3f 100644 --- a/pkg/extensions/search/common/oci_layout.go +++ b/pkg/extensions/search/common/oci_layout.go @@ -7,7 +7,6 @@ import ( "fmt" "path" "strconv" - "time" v1 "github.com/google/go-containerregistry/pkg/v1" notreg "github.com/notaryproject/notation-go/registry" @@ -24,7 +23,6 @@ type OciLayoutUtils interface { //nolint: interfacebloat GetImageBlobManifest(imageDir string, digest godigest.Digest) (v1.Manifest, error) GetImageInfo(imageDir string, hash v1.Hash) (ispec.Image, error) GetImageTagsWithTimestamp(repo string) ([]TagInfo, error) - GetImageLastUpdated(imageInfo ispec.Image) time.Time GetImagePlatform(imageInfo ispec.Image) (string, string) GetImageManifestSize(repo string, manifestDigest godigest.Digest) int64 GetRepoLastUpdated(repo string) (TagInfo, error) @@ -189,13 +187,7 @@ func (olu BaseOciLayoutUtils) GetImageTagsWithTimestamp(repo string) ([]TagInfo, return tagsInfo, err } - var timeStamp time.Time - - if len(imageInfo.History) != 0 { - timeStamp = *imageInfo.History[0].Created - } else { - timeStamp = time.Time{} - } + timeStamp := GetImageLastUpdated(imageInfo) tagsInfo = append(tagsInfo, TagInfo{Name: val, Timestamp: timeStamp, Digest: digest.String()}) } @@ -250,18 +242,6 @@ func (olu BaseOciLayoutUtils) CheckManifestSignature(name string, digest godiges return true } -func (olu BaseOciLayoutUtils) GetImageLastUpdated(imageInfo ispec.Image) time.Time { - var timeStamp time.Time - - if len(imageInfo.History) != 0 { - timeStamp = *imageInfo.History[0].Created - } else { - timeStamp = time.Time{} - } - - return timeStamp -} - func (olu BaseOciLayoutUtils) GetImagePlatform(imageConfig ispec.Image) ( string, string, ) { @@ -413,7 +393,7 @@ func (olu BaseOciLayoutUtils) GetExpandedRepoInfo(name string) (RepoInfo, error) size := strconv.Itoa(int(imageSize)) manifestDigest := man.Digest.Hex() configDigest := manifest.Config.Digest.Hex - lastUpdated := olu.GetImageLastUpdated(imageConfigInfo) + lastUpdated := GetImageLastUpdated(imageConfigInfo) score := 0 imageSummary := ImageSummary{ diff --git a/pkg/extensions/search/resolver.go b/pkg/extensions/search/resolver.go index 13efc807..34f537e3 100644 --- a/pkg/extensions/search/resolver.go +++ b/pkg/extensions/search/resolver.go @@ -10,7 +10,6 @@ import ( "sort" "strconv" "strings" - "time" "github.com/99designs/gqlgen/graphql" glob "github.com/bmatcuk/doublestar/v4" //nolint:gci @@ -211,7 +210,7 @@ func repoListWithNewestImage( manifestDigest := manifest.Digest.Hex() configDigest := imageBlobManifest.Config.Digest.Hex isSigned := olu.CheckManifestSignature(repo, manifest.Digest) - lastUpdated := olu.GetImageLastUpdated(imageConfigInfo) + lastUpdated := common.GetImageLastUpdated(imageConfigInfo) score := 0 imageSummary := gql_generated.ImageSummary{ @@ -371,7 +370,7 @@ func globalSearch(repoList []string, name, tag string, olu common.OciLayoutUtils // update matching score score := calculateImageMatchingScore(repo, index, matchesTag) - lastUpdated := olu.GetImageLastUpdated(imageConfigInfo) + lastUpdated := common.GetImageLastUpdated(imageConfigInfo) os, arch := olu.GetImagePlatform(imageConfigInfo) osArch := &gql_generated.OsArch{ Os: &os, @@ -569,13 +568,7 @@ func BuildImageInfo(repo string, tag string, manifestDigest godigest.Digest, allHistory := []*gql_generated.LayerHistory{} formattedManifestDigest := manifestDigest.Hex() annotations := common.GetAnnotations(manifest.Annotations, imageConfig.Config.Labels) - - lastUpdated := imageConfig.Created - - if (lastUpdated == nil || *lastUpdated == (time.Time{})) && - len(imageConfig.History) > 0 { - lastUpdated = imageConfig.History[len(imageConfig.History)-1].Created - } + lastUpdated := common.GetImageLastUpdated(imageConfig) history := imageConfig.History if len(history) == 0 { @@ -617,7 +610,7 @@ func BuildImageInfo(repo string, tag string, manifestDigest godigest.Digest, Licenses: &annotations.Licenses, Labels: &annotations.Labels, Source: &annotations.Source, - LastUpdated: lastUpdated, + LastUpdated: &lastUpdated, IsSigned: &isSigned, Platform: &gql_generated.OsArch{ Os: &imageConfig.OS, @@ -666,7 +659,7 @@ func BuildImageInfo(repo string, tag string, manifestDigest godigest.Digest, Licenses: &annotations.Licenses, Labels: &annotations.Labels, Source: &annotations.Source, - LastUpdated: lastUpdated, + LastUpdated: &lastUpdated, IsSigned: &isSigned, Platform: &gql_generated.OsArch{ Os: &imageConfig.OS, @@ -711,7 +704,7 @@ func BuildImageInfo(repo string, tag string, manifestDigest godigest.Digest, Licenses: &annotations.Licenses, Labels: &annotations.Labels, Source: &annotations.Source, - LastUpdated: lastUpdated, + LastUpdated: &lastUpdated, IsSigned: &isSigned, Platform: &gql_generated.OsArch{ Os: &imageConfig.OS, diff --git a/pkg/test/mocks/oci_mock.go b/pkg/test/mocks/oci_mock.go index cb9bd1a6..6bdb123a 100644 --- a/pkg/test/mocks/oci_mock.go +++ b/pkg/test/mocks/oci_mock.go @@ -1,8 +1,6 @@ package mocks import ( - "time" - v1 "github.com/google/go-containerregistry/pkg/v1" godigest "github.com/opencontainers/go-digest" ispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -15,7 +13,6 @@ type OciLayoutUtilsMock struct { GetImageBlobManifestFn func(imageDir string, digest godigest.Digest) (v1.Manifest, error) GetImageInfoFn func(imageDir string, hash v1.Hash) (ispec.Image, error) GetImageTagsWithTimestampFn func(repo string) ([]common.TagInfo, error) - GetImageLastUpdatedFn func(imageInfo ispec.Image) time.Time GetImagePlatformFn func(imageInfo ispec.Image) (string, string) GetImageVendorFn func(imageInfo ispec.Image) string GetImageManifestSizeFn func(repo string, manifestDigest godigest.Digest) int64 @@ -75,14 +72,6 @@ func (olum OciLayoutUtilsMock) GetImageTagsWithTimestamp(repo string) ([]common. return []common.TagInfo{}, nil } -func (olum OciLayoutUtilsMock) GetImageLastUpdated(imageInfo ispec.Image) time.Time { - if olum.GetImageLastUpdatedFn != nil { - return olum.GetImageLastUpdatedFn(imageInfo) - } - - return time.Time{} -} - func (olum OciLayoutUtilsMock) GetImagePlatform(imageInfo ispec.Image) (string, string) { if olum.GetImagePlatformFn != nil { return olum.GetImagePlatformFn(imageInfo)