0
Fork 0
mirror of https://github.com/project-zot/zot.git synced 2024-12-30 22:34:13 -05:00

feat(search): add artifact type to manifest summary gql structure (#1448)

Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
LaurentiuNiculae 2023-05-15 20:44:49 +03:00 committed by GitHub
parent 912854f29b
commit f4501e6b6b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 202 additions and 3 deletions

View file

@ -53,6 +53,8 @@ type ManifestSummary struct {
Layers []LayerSummary `json:"layers"`
History []LayerHistory `json:"history"`
Vulnerabilities ImageVulnerabilitySummary `json:"vulnerabilities"`
Referrers []Referrer `json:"referrers"`
ArtifactType string `json:"artifactType"`
}
type Platform struct {

View file

@ -301,6 +301,7 @@ func ImageManifest2ImageSummary(ctx context.Context, repo, tag string, digest go
repoName = repo
configDigest = manifestContent.Config.Digest.String()
configSize = manifestContent.Config.Size
artifactType = common.GetManifestArtifactType(manifestContent)
imageLastUpdated = common.GetImageLastUpdated(configContent)
downloadCount = repoMeta.Statistics[digest.String()].DownloadCount
isSigned = false
@ -373,6 +374,8 @@ func ImageManifest2ImageSummary(ctx context.Context, repo, tag string, digest go
MaxSeverity: &imageCveSummary.MaxSeverity,
Count: &imageCveSummary.Count,
},
Referrers: getReferrers(repoMeta.Referrers[manifestDigest]),
ArtifactType: &artifactType,
},
},
LastUpdated: &imageLastUpdated,
@ -437,8 +440,7 @@ func ImageManifest2ManifestSummary(ctx context.Context, repo, tag string, descri
) (*gql_generated.ManifestSummary, map[string]int64, error) {
var (
manifestContent ispec.Manifest
digest = descriptor.Digest
digest = descriptor.Digest
)
err := json.Unmarshal(manifestMeta.ManifestBlob, &manifestContent)
@ -463,6 +465,7 @@ func ImageManifest2ManifestSummary(ctx context.Context, repo, tag string, descri
manifestDigestStr = digest.String()
configDigest = manifestContent.Config.Digest.String()
configSize = manifestContent.Config.Size
artifactType = common.GetManifestArtifactType(manifestContent)
imageLastUpdated = common.GetImageLastUpdated(configContent)
downloadCount = manifestMeta.DownloadCount
isSigned = false
@ -522,7 +525,8 @@ func ImageManifest2ManifestSummary(ctx context.Context, repo, tag string, descri
MaxSeverity: &imageCveSummary.MaxSeverity,
Count: &imageCveSummary.Count,
},
Referrers: getReferrers(referrersInfo),
Referrers: getReferrers(referrersInfo),
ArtifactType: &artifactType,
}
return &manifestSummary, imageBlobsMap, nil

View file

@ -115,6 +115,7 @@ type ComplexityRoot struct {
}
ManifestSummary struct {
ArtifactType func(childComplexity int) int
ConfigDigest func(childComplexity int) int
Digest func(childComplexity int) int
DownloadCount func(childComplexity int) int
@ -538,6 +539,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.LayerSummary.Size(childComplexity), true
case "ManifestSummary.ArtifactType":
if e.complexity.ManifestSummary.ArtifactType == nil {
break
}
return e.complexity.ManifestSummary.ArtifactType(childComplexity), true
case "ManifestSummary.ConfigDigest":
if e.complexity.ManifestSummary.ConfigDigest == nil {
break
@ -1278,6 +1286,10 @@ type ManifestSummary {
Information about objects that reference this image
"""
Referrers: [Referrer]
"""
Value of the artifactType field if present else the value of the config media type
"""
ArtifactType: String
}
"""
@ -3248,6 +3260,8 @@ func (ec *executionContext) fieldContext_ImageSummary_Manifests(ctx context.Cont
return ec.fieldContext_ManifestSummary_Vulnerabilities(ctx, field)
case "Referrers":
return ec.fieldContext_ManifestSummary_Referrers(ctx, field)
case "ArtifactType":
return ec.fieldContext_ManifestSummary_ArtifactType(ctx, field)
}
return nil, fmt.Errorf("no field named %q was found under type ManifestSummary", field.Name)
},
@ -4598,6 +4612,47 @@ func (ec *executionContext) fieldContext_ManifestSummary_Referrers(ctx context.C
return fc, nil
}
func (ec *executionContext) _ManifestSummary_ArtifactType(ctx context.Context, field graphql.CollectedField, obj *ManifestSummary) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_ManifestSummary_ArtifactType(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.ArtifactType, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_ManifestSummary_ArtifactType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "ManifestSummary",
Field: field,
IsMethod: false,
IsResolver: false,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _PackageInfo_Name(ctx context.Context, field graphql.CollectedField, obj *PackageInfo) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_PackageInfo_Name(ctx, field)
if err != nil {
@ -9282,6 +9337,10 @@ func (ec *executionContext) _ManifestSummary(ctx context.Context, sel ast.Select
out.Values[i] = ec._ManifestSummary_Referrers(ctx, field, obj)
case "ArtifactType":
out.Values[i] = ec._ManifestSummary_ArtifactType(ctx, field, obj)
default:
panic("unknown field " + strconv.Quote(field.Name))
}

View file

@ -181,6 +181,8 @@ type ManifestSummary struct {
Vulnerabilities *ImageVulnerabilitySummary `json:"Vulnerabilities,omitempty"`
// Information about objects that reference this image
Referrers []*Referrer `json:"Referrers,omitempty"`
// Value of the artifactType field if present else the value of the config media type
ArtifactType *string `json:"ArtifactType,omitempty"`
}
// Contains the name of the package, the current installed version and the version where the CVE was fixed

View file

@ -242,6 +242,10 @@ type ManifestSummary {
Information about objects that reference this image
"""
Referrers: [Referrer]
"""
Value of the artifactType field if present else the value of the config media type
"""
ArtifactType: String
}
"""

View file

@ -6456,4 +6456,132 @@ func TestImageSummary(t *testing.T) {
// There are 0 vulnerabilities this data used in tests
So(imgSummary.Vulnerabilities.MaxSeverity, ShouldEqual, "CRITICAL")
})
Convey("GraphQL query for Artifact Type", t, func() {
port := GetFreePort()
baseURL := GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
conf.Storage.RootDirectory = t.TempDir()
conf.Storage.GC = false
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
}
conf.Extensions.Search.CVE = nil
ctlr := api.NewController(conf)
query := `
{
Image(image:"repo:art%d"){
RepoName
Tag
Manifests {
Digest
ArtifactType
}
Size
}
}`
queryImg1 := fmt.Sprintf(query, 1)
queryImg2 := fmt.Sprintf(query, 2)
var imgSummaryResponse ImageSummaryResult
ctlrManager := NewControllerManager(ctlr)
ctlrManager.StartAndWait(port)
defer ctlrManager.StopServer()
// upload the images
artType1 := "application/test.signature.v1"
artType2 := "application/test.signature.v2"
img1, err := GetRandomImage("art1")
So(err, ShouldBeNil)
img1.Manifest.Config = ispec.ScratchDescriptor
img1.Manifest.ArtifactType = artType1
digest1, err := img1.Digest()
So(err, ShouldBeNil)
err = UploadImage(img1, baseURL, "repo")
So(err, ShouldBeNil)
img2, err := GetRandomImage("art2")
So(err, ShouldBeNil)
img2.Manifest.Config.MediaType = artType2
digest2, err := img2.Digest()
So(err, ShouldBeNil)
err = UploadImage(img2, baseURL, "repo")
So(err, ShouldBeNil)
// GET image 1
resp, err := resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(queryImg1))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
So(resp.Body(), ShouldNotBeNil)
err = json.Unmarshal(resp.Body(), &imgSummaryResponse)
So(err, ShouldBeNil)
imgSum := imgSummaryResponse.SingleImageSummary.ImageSummary
So(len(imgSum.Manifests), ShouldEqual, 1)
So(imgSum.Manifests[0].ArtifactType, ShouldResemble, artType1)
// GET image 2
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(queryImg2))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
So(resp.Body(), ShouldNotBeNil)
err = json.Unmarshal(resp.Body(), &imgSummaryResponse)
So(err, ShouldBeNil)
imgSum = imgSummaryResponse.SingleImageSummary.ImageSummary
So(len(imgSum.Manifests), ShouldEqual, 1)
So(imgSum.Manifests[0].ArtifactType, ShouldResemble, artType2)
// Expanded repo info test
queryExpRepoInfo := `{
ExpandedRepoInfo(repo:"test1"){
Images {
Tag
Manifests {
Digest
ArtifactType
}
}
}
}`
var expandedRepoInfoResp ExpandedRepoInfoResp
resp, err = resty.R().Get(baseURL + graphqlQueryPrefix + "?query=" +
url.QueryEscape(queryExpRepoInfo))
So(resp, ShouldNotBeNil)
So(err, ShouldBeNil)
So(resp.StatusCode(), ShouldEqual, 200)
So(resp.Body(), ShouldNotBeNil)
err = json.Unmarshal(resp.Body(), &expandedRepoInfoResp)
So(err, ShouldBeNil)
imgSums := expandedRepoInfoResp.ExpandedRepoInfo.RepoInfo.ImageSummaries
for _, imgSum := range imgSums {
switch imgSum.Digest {
case digest1.String():
So(imgSum.Manifests[0].ArtifactType, ShouldResemble, artType1)
case digest2.String():
So(imgSum.Manifests[0].ArtifactType, ShouldResemble, artType2)
}
}
})
}