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:
parent
912854f29b
commit
f4501e6b6b
6 changed files with 202 additions and 3 deletions
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
"""
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue