0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2025-01-13 22:50:38 -05:00

fix(convert): now returned annotations for an index will fallback to annotations from a random manifest if the annotations field is not present on the index manifest (#1667)

Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
LaurentiuNiculae 2023-08-07 10:25:05 +03:00 committed by GitHub
parent cad564b9ee
commit fce9a02ed5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 293 additions and 3 deletions

View file

@ -154,7 +154,7 @@ func searchCve(searchConfig searchConfig) error {
}
for _, searcher := range searchers {
// there can be CVE DB readyness issues on the server side
// there can be CVE DB readiness issues on the server side
// we need a retry mechanism for that specific type of errors
maxAttempts := 20

View file

@ -133,3 +133,58 @@ func GetAnnotations(annotations, labels map[string]string) ImageAnnotations {
Authors: authors,
}
}
func GetIndexAnnotations(indexAnnotations, manifestAnnotations, manifestLabels map[string]string) ImageAnnotations {
annotationsFromManifest := GetAnnotations(manifestAnnotations, manifestLabels)
description := GetDescription(indexAnnotations)
if description == "" {
description = annotationsFromManifest.Description
}
title := GetTitle(indexAnnotations)
if title == "" {
title = annotationsFromManifest.Title
}
documentation := GetDocumentation(indexAnnotations)
if documentation == "" {
documentation = annotationsFromManifest.Documentation
}
source := GetSource(indexAnnotations)
if source == "" {
source = annotationsFromManifest.Source
}
licenses := GetLicenses(indexAnnotations)
if licenses == "" {
licenses = annotationsFromManifest.Licenses
}
categories := GetCategories(indexAnnotations)
if categories == "" {
categories = annotationsFromManifest.Labels
}
vendor := GetVendor(indexAnnotations)
if vendor == "" {
vendor = annotationsFromManifest.Vendor
}
authors := GetAuthors(indexAnnotations)
if authors == "" {
authors = annotationsFromManifest.Authors
}
return ImageAnnotations{
Description: description,
Title: title,
Documentation: documentation,
Source: source,
Licenses: licenses,
Labels: categories,
Vendor: vendor,
Authors: authors,
}
}

View file

@ -770,3 +770,213 @@ func TestPaginatedConvert(t *testing.T) {
So(pageInfo.ItemCount, ShouldEqual, 1)
})
}
func TestGetOneManifestAnnotations(t *testing.T) {
Convey("GetOneManifestAnnotations errors", t, func() {
manifestAnnotations, configLabels := convert.GetOneManifestAnnotations(
ispec.Index{Manifests: []ispec.Descriptor{
{Digest: "bad-manifest"}, {Digest: "dig2"},
}},
map[string]mTypes.ManifestMetadata{
"bad-manifest": {
ManifestBlob: []byte(`bad`),
ConfigBlob: []byte("{}"),
},
},
)
So(manifestAnnotations, ShouldBeEmpty)
So(configLabels, ShouldBeEmpty)
manifestAnnotations, configLabels = convert.GetOneManifestAnnotations(
ispec.Index{Manifests: []ispec.Descriptor{
{Digest: "bad-config"},
}},
map[string]mTypes.ManifestMetadata{
"bad-config": {
ManifestBlob: []byte("{}"),
ConfigBlob: []byte("bad"),
},
},
)
So(manifestAnnotations, ShouldBeEmpty)
So(configLabels, ShouldBeEmpty)
})
Convey("Test ImageIndex2ImageSummary annotations logic", t, func() {
ctx := context.Background()
configLabels := map[string]string{
ispec.AnnotationDescription: "ConfigDescription",
ispec.AnnotationLicenses: "ConfigLicenses",
ispec.AnnotationVendor: "ConfigVendor",
ispec.AnnotationAuthors: "ConfigAuthors",
ispec.AnnotationTitle: "ConfigTitle",
ispec.AnnotationDocumentation: "ConfigDocumentation",
ispec.AnnotationSource: "ConfigSource",
}
manifestAnnotations := map[string]string{
ispec.AnnotationDescription: "ManifestDescription",
ispec.AnnotationLicenses: "ManifestLicenses",
ispec.AnnotationVendor: "ManifestVendor",
ispec.AnnotationAuthors: "ManifestAuthors",
ispec.AnnotationTitle: "ManifestTitle",
ispec.AnnotationDocumentation: "ManifestDocumentation",
ispec.AnnotationSource: "ManifestSource",
}
indexAnnotations := map[string]string{
ispec.AnnotationDescription: "IndexDescription",
ispec.AnnotationLicenses: "IndexLicenses",
ispec.AnnotationVendor: "IndexVendor",
ispec.AnnotationAuthors: "IndexAuthors",
ispec.AnnotationTitle: "IndexTitle",
ispec.AnnotationDocumentation: "IndexDocumentation",
ispec.AnnotationSource: "IndexSource",
}
imageWithConfigAnnotations := test.CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{
Config: ispec.ImageConfig{
Labels: configLabels,
},
}).Build()
imageWithManifestAndConfigAnnotations := test.CreateImageWith().DefaultLayers().
ImageConfig(ispec.Image{
Config: ispec.ImageConfig{
Labels: configLabels,
},
}).Annotations(manifestAnnotations).Build()
// --------------------------------------------------------
indexWithAnnotations := test.CreateMultiarchWith().Images(
[]test.Image{imageWithManifestAndConfigAnnotations},
).Annotations(indexAnnotations).Build()
repoMeta, manifestMetadata, indexData := test.GetMetadataForRepos(test.Repo{
Name: "repo",
MultiArchImages: []test.RepoMultiArchImage{
{MultiarchImage: indexWithAnnotations, Tag: "tag"},
},
})
digest := indexWithAnnotations.Digest()
imageSummary, _, err := convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest, true, repoMeta[0],
indexData[digest.String()], manifestMetadata, nil)
So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldResemble, "IndexDescription")
So(*imageSummary.Licenses, ShouldResemble, "IndexLicenses")
So(*imageSummary.Title, ShouldResemble, "IndexTitle")
So(*imageSummary.Source, ShouldResemble, "IndexSource")
So(*imageSummary.Documentation, ShouldResemble, "IndexDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "IndexVendor")
So(*imageSummary.Authors, ShouldResemble, "IndexAuthors")
// --------------------------------------------------------
indexWithManifestAndConfigAnnotations := test.CreateMultiarchWith().Images(
[]test.Image{imageWithManifestAndConfigAnnotations, test.CreateRandomImage(), test.CreateRandomImage()},
).Build()
repoMeta, manifestMetadata, indexData = test.GetMetadataForRepos(test.Repo{
Name: "repo",
MultiArchImages: []test.RepoMultiArchImage{{MultiarchImage: indexWithManifestAndConfigAnnotations}},
})
digest = indexWithManifestAndConfigAnnotations.Digest()
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest,
true, repoMeta[0], indexData[digest.String()], manifestMetadata, nil)
So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldResemble, "ManifestDescription")
So(*imageSummary.Licenses, ShouldResemble, "ManifestLicenses")
So(*imageSummary.Title, ShouldResemble, "ManifestTitle")
So(*imageSummary.Source, ShouldResemble, "ManifestSource")
So(*imageSummary.Documentation, ShouldResemble, "ManifestDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "ManifestVendor")
So(*imageSummary.Authors, ShouldResemble, "ManifestAuthors")
// --------------------------------------------------------
indexWithConfigAnnotations := test.CreateMultiarchWith().Images(
[]test.Image{imageWithConfigAnnotations, test.CreateRandomImage(), test.CreateRandomImage()},
).Build()
repoMeta, manifestMetadata, indexData = test.GetMetadataForRepos(test.Repo{
Name: "repo",
MultiArchImages: []test.RepoMultiArchImage{{MultiarchImage: indexWithConfigAnnotations, Tag: "tag"}},
})
digest = indexWithConfigAnnotations.Digest()
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest,
true, repoMeta[0], indexData[digest.String()], manifestMetadata, nil)
So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldResemble, "ConfigDescription")
So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses")
So(*imageSummary.Title, ShouldResemble, "ConfigTitle")
So(*imageSummary.Source, ShouldResemble, "ConfigSource")
So(*imageSummary.Documentation, ShouldResemble, "ConfigDocumentation")
So(*imageSummary.Vendor, ShouldResemble, "ConfigVendor")
So(*imageSummary.Authors, ShouldResemble, "ConfigAuthors")
//--------------------------------------------------------
indexWithMixAnnotations := test.CreateMultiarchWith().Images(
[]test.Image{
test.CreateImageWith().DefaultLayers().ImageConfig(ispec.Image{
Config: ispec.ImageConfig{
Labels: map[string]string{
ispec.AnnotationDescription: "ConfigDescription",
ispec.AnnotationLicenses: "ConfigLicenses",
},
},
}).Annotations(map[string]string{
ispec.AnnotationVendor: "ManifestVendor",
ispec.AnnotationAuthors: "ManifestAuthors",
}).Build(),
test.CreateRandomImage(),
test.CreateRandomImage(),
},
).Annotations(
map[string]string{
ispec.AnnotationTitle: "IndexTitle",
ispec.AnnotationDocumentation: "IndexDocumentation",
ispec.AnnotationSource: "IndexSource",
},
).Build()
repoMeta, manifestMetadata, indexData = test.GetMetadataForRepos(test.Repo{
Name: "repo",
MultiArchImages: []test.RepoMultiArchImage{{MultiarchImage: indexWithMixAnnotations, Tag: "tag"}},
})
digest = indexWithMixAnnotations.Digest()
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest,
true, repoMeta[0], indexData[digest.String()], manifestMetadata, nil)
So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldResemble, "ConfigDescription")
So(*imageSummary.Licenses, ShouldResemble, "ConfigLicenses")
So(*imageSummary.Vendor, ShouldResemble, "ManifestVendor")
So(*imageSummary.Authors, ShouldResemble, "ManifestAuthors")
So(*imageSummary.Title, ShouldResemble, "IndexTitle")
So(*imageSummary.Documentation, ShouldResemble, "IndexDocumentation")
So(*imageSummary.Source, ShouldResemble, "IndexSource")
//--------------------------------------------------------
indexWithNoAnnotations := test.CreateRandomMultiarch()
repoMeta, manifestMetadata, indexData = test.GetMetadataForRepos(test.Repo{
Name: "repo",
MultiArchImages: []test.RepoMultiArchImage{{MultiarchImage: indexWithNoAnnotations, Tag: "tag"}},
})
digest = indexWithNoAnnotations.Digest()
imageSummary, _, err = convert.ImageIndex2ImageSummary(ctx, "repo", "tag", digest,
true, repoMeta[0], indexData[digest.String()], manifestMetadata, nil)
So(err, ShouldBeNil)
So(*imageSummary.Description, ShouldBeBlank)
So(*imageSummary.Licenses, ShouldBeBlank)
So(*imageSummary.Vendor, ShouldBeBlank)
So(*imageSummary.Authors, ShouldBeBlank)
So(*imageSummary.Title, ShouldBeBlank)
So(*imageSummary.Documentation, ShouldBeBlank)
So(*imageSummary.Source, ShouldBeBlank)
})
}

View file

@ -268,10 +268,11 @@ func ImageIndex2ImageSummary(ctx context.Context, repo, tag string, indexDigest
indexSize = strconv.FormatInt(totalIndexSize, 10)
annotations := GetAnnotations(indexContent.Annotations, map[string]string{})
signaturesInfo := GetSignaturesInfo(isSigned, repoMeta, indexDigest)
manifestAnnotations, configLabels := GetOneManifestAnnotations(indexContent, manifestMetaMap)
annotations := GetIndexAnnotations(indexContent.Annotations, manifestAnnotations, configLabels)
indexSummary := gql_generated.ImageSummary{
RepoName: &repo,
Tag: &tag,
@ -301,6 +302,30 @@ func ImageIndex2ImageSummary(ctx context.Context, repo, tag string, indexDigest
return &indexSummary, indexBlobs, nil
}
func GetOneManifestAnnotations(indexContent ispec.Index, manifestMetaMap map[string]mTypes.ManifestMetadata,
) (map[string]string, map[string]string) {
if len(manifestMetaMap) == 0 || len(indexContent.Manifests) == 0 {
return map[string]string{}, map[string]string{}
}
manifestMeta := manifestMetaMap[indexContent.Manifests[0].Digest.String()]
manifestContent := ispec.Manifest{}
configContent := ispec.Image{}
err := json.Unmarshal(manifestMeta.ManifestBlob, &manifestContent)
if err != nil {
return map[string]string{}, map[string]string{}
}
err = json.Unmarshal(manifestMeta.ConfigBlob, &configContent)
if err != nil {
return map[string]string{}, map[string]string{}
}
return manifestContent.Annotations, configContent.Config.Labels
}
func ImageManifest2ImageSummary(ctx context.Context, repo, tag string, digest godigest.Digest, skipCVE bool,
repoMeta mTypes.RepoMetadata, manifestMeta mTypes.ManifestMetadata, cveInfo cveinfo.CveInfo,
) (*gql_generated.ImageSummary, map[string]int64, error) {