mirror of
https://github.com/project-zot/zot.git
synced 2025-03-18 02:22:53 -05:00
feat(cli): updated display format for multiarch images (#1268)
Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
parent
0036d6dd09
commit
21b7c69fd9
12 changed files with 734 additions and 184 deletions
|
@ -326,12 +326,14 @@ func fetchImageIndexStruct(ctx context.Context, job *httpJob) (*imageStruct, err
|
|||
isNotationSigned(ctx, job.imageName, indexDigest, job.config, job.username, job.password)
|
||||
|
||||
return &imageStruct{
|
||||
verbose: *job.config.verbose,
|
||||
RepoName: job.imageName,
|
||||
Tag: job.tagName,
|
||||
Digest: indexDigest,
|
||||
MediaType: ispec.MediaTypeImageIndex,
|
||||
Manifests: manifestList,
|
||||
Size: strconv.FormatInt(imageSize, 10),
|
||||
IsSigned: isIndexSigned,
|
||||
Manifests: manifestList,
|
||||
verbose: *job.config.verbose,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -351,14 +353,16 @@ func fetchImageManifestStruct(ctx context.Context, job *httpJob) (*imageStruct,
|
|||
}
|
||||
|
||||
return &imageStruct{
|
||||
verbose: *job.config.verbose,
|
||||
RepoName: job.imageName,
|
||||
Tag: job.tagName,
|
||||
Size: manifest.Size,
|
||||
IsSigned: manifest.IsSigned,
|
||||
RepoName: job.imageName,
|
||||
Tag: job.tagName,
|
||||
Digest: manifest.Digest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Manifests: []manifestStruct{
|
||||
manifest,
|
||||
},
|
||||
Size: manifest.Size,
|
||||
IsSigned: manifest.IsSigned,
|
||||
verbose: *job.config.verbose,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
|
@ -264,6 +265,7 @@ func TestDoHTTPRequest(t *testing.T) {
|
|||
vars := mux.Vars(req)
|
||||
|
||||
if vars["reference"] == "indexRef" {
|
||||
writer.Header().Add("docker-content-digest", godigest.FromString("t").String())
|
||||
_, err := writer.Write([]byte(`
|
||||
{
|
||||
"manifests": [
|
||||
|
@ -592,6 +594,7 @@ func TestDoJobErrors(t *testing.T) {
|
|||
Route: "/v2/{name}/manifests/{reference}",
|
||||
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Type", ispec.MediaTypeImageIndex)
|
||||
w.Header().Add("docker-content-digest", godigest.FromString("t").String())
|
||||
|
||||
_, err := w.Write([]byte(""))
|
||||
if err != nil {
|
||||
|
@ -606,6 +609,8 @@ func TestDoJobErrors(t *testing.T) {
|
|||
vars := mux.Vars(req)
|
||||
|
||||
if vars["reference"] == "indexRef" {
|
||||
writer.Header().Add("docker-content-digest", godigest.FromString("t").String())
|
||||
|
||||
_, err := writer.Write([]byte(`{"manifests": [{"digest": "manifestRef"}]}`))
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -613,6 +618,8 @@ func TestDoJobErrors(t *testing.T) {
|
|||
}
|
||||
|
||||
if vars["reference"] == "manifestRef" {
|
||||
writer.Header().Add("docker-content-digest", godigest.FromString("t").String())
|
||||
|
||||
_, err := writer.Write([]byte(`{"config": {"digest": "confDigest"}}`))
|
||||
if err != nil {
|
||||
return
|
||||
|
|
|
@ -183,7 +183,7 @@ func TestSearchCVECmd(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE dummyImageName tag 6e2f80bf os/arch false 123kB")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE dummyImageName tag os/arch 6e2f80bf false 123kB")
|
||||
})
|
||||
|
||||
Convey("Test CVE by name and CVE ID - using shorthand", t, func() {
|
||||
|
@ -200,7 +200,7 @@ func TestSearchCVECmd(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE dummyImageName tag 6e2f80bf os/arch false 123kB")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE dummyImageName tag os/arch 6e2f80bf false 123kB")
|
||||
})
|
||||
|
||||
Convey("Test CVE by image name - in text format", t, func() {
|
||||
|
@ -283,7 +283,7 @@ func TestSearchCVECmd(t *testing.T) {
|
|||
err := cveCmd.Execute()
|
||||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE anImage tag 6e2f80bf os/arch false 123kB") //nolint:lll
|
||||
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE anImage tag os/arch 6e2f80bf false 123kB") //nolint:lll
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
|
@ -328,7 +328,7 @@ func TestSearchCVECmd(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE fixedImage tag 6e2f80bf os/arch false 123kB") //nolint:lll
|
||||
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE fixedImage tag os/arch 6e2f80bf false 123kB") //nolint:lll
|
||||
})
|
||||
|
||||
Convey("Test fixed tags by and image name CVE ID - invalid image name", t, func() {
|
||||
|
@ -713,7 +713,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldBeNil)
|
||||
So(str, ShouldEqual, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE zot-cve-test 0.0.1 82836dd7 N/A false 548B")
|
||||
So(str, ShouldEqual, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 82836dd7 false 548B")
|
||||
})
|
||||
|
||||
Convey("Test images by CVE ID - GQL - invalid CVE ID", t, func() {
|
||||
|
@ -730,7 +730,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldBeNil)
|
||||
So(str, ShouldNotContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(str, ShouldNotContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
})
|
||||
|
||||
Convey("Test images by CVE ID - GQL - invalid output format", t, func() {
|
||||
|
@ -778,7 +778,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.TrimSpace(str), ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(strings.TrimSpace(str), ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
})
|
||||
|
||||
Convey("Test fixed tags by image name and CVE ID - GQL - random image", t, func() {
|
||||
|
@ -795,7 +795,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldNotBeNil)
|
||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
})
|
||||
|
||||
Convey("Test fixed tags by image name and CVE ID - GQL - invalid image", t, func() {
|
||||
|
@ -812,7 +812,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldNotBeNil)
|
||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
})
|
||||
|
||||
Convey("Test CVE by name and CVE ID - GQL - positive", t, func() {
|
||||
|
@ -829,7 +829,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE zot-cve-test 0.0.1 82836dd7 N/A false 548B")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 82836dd7 false 548B")
|
||||
})
|
||||
|
||||
Convey("Test CVE by name and CVE ID - GQL - invalid name and CVE ID", t, func() {
|
||||
|
@ -845,7 +845,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "IMAGE NAME TAG SIGNED SIZE")
|
||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "IMAGE NAME TAG OS/ARCH SIGNED SIZE")
|
||||
})
|
||||
|
||||
Convey("Test CVE by name and CVE ID - GQL - invalid output format", t, func() {
|
||||
|
@ -907,7 +907,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldBeNil)
|
||||
So(str, ShouldEqual, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE zot-cve-test 0.0.1 82836dd7 linux/amd64 false 548B")
|
||||
So(str, ShouldEqual, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 82836dd7 false 548B")
|
||||
})
|
||||
|
||||
Convey("Test images by CVE ID - invalid CVE ID", t, func() {
|
||||
|
@ -924,7 +924,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldBeNil)
|
||||
So(str, ShouldNotContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(str, ShouldNotContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
})
|
||||
|
||||
Convey("Test fixed tags by and image name CVE ID - positive", t, func() {
|
||||
|
@ -958,7 +958,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.TrimSpace(str), ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(strings.TrimSpace(str), ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
})
|
||||
|
||||
Convey("Test fixed tags by and image name CVE ID - invalid image", t, func() {
|
||||
|
@ -975,7 +975,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
str = strings.TrimSpace(str)
|
||||
So(err, ShouldNotBeNil)
|
||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(strings.TrimSpace(str), ShouldNotContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
})
|
||||
|
||||
Convey("Test CVE by name and CVE ID - positive", t, func() {
|
||||
|
@ -992,7 +992,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE zot-cve-test 0.0.1 82836dd7 linux/amd64 false 548B")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE zot-cve-test 0.0.1 linux/amd64 82836dd7 false 548B")
|
||||
})
|
||||
|
||||
Convey("Test CVE by name and CVE ID - invalid name and CVE ID", t, func() {
|
||||
|
@ -1009,7 +1009,7 @@ func TestServerCVEResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.TrimSpace(str), ShouldNotContainSubstring,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -186,7 +186,7 @@ func TestSearchImageCmd(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE dummyImageName tag 6e2f80bf os/arch false 123kB")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE dummyImageName tag os/arch 6e2f80bf false 123kB")
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
|
@ -203,7 +203,7 @@ func TestSearchImageCmd(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE dummyImageName tag 6e2f80bf os/arch false 123kB")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE dummyImageName tag os/arch 6e2f80bf false 123kB")
|
||||
So(err, ShouldBeNil)
|
||||
Convey("using shorthand", func() {
|
||||
args := []string{"imagetest", "-n", "dummyImageName", "--url", "someUrlImage"}
|
||||
|
@ -219,7 +219,7 @@ func TestSearchImageCmd(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE dummyImageName tag 6e2f80bf os/arch false 123kB")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE dummyImageName tag os/arch 6e2f80bf false 123kB")
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
})
|
||||
|
@ -237,7 +237,7 @@ func TestSearchImageCmd(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE anImage tag 6e2f80bf os/arch false 123kB")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE anImage tag os/arch 6e2f80bf false 123kB")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("invalid URL format", func() {
|
||||
|
@ -330,8 +330,8 @@ func TestSignature(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 6742241d linux/amd64 true 447B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 6742241d true 447B")
|
||||
|
||||
t.Log("Test getting all images using rest calls to get catalog and individual manifests")
|
||||
cmd = MockNewImageCommand(new(searchService))
|
||||
|
@ -343,8 +343,8 @@ func TestSignature(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
str = space.ReplaceAllString(buff.String(), " ")
|
||||
actual = strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 6742241d linux/amd64 true 447B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 6742241d true 447B")
|
||||
|
||||
err = os.Chdir(currentWorkingDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -407,8 +407,8 @@ func TestSignature(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 0.0.1 6742241d linux/amd64 true 447B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 0.0.1 linux/amd64 6742241d true 447B")
|
||||
|
||||
t.Log("Test getting all images using rest calls to get catalog and individual manifests")
|
||||
cmd = MockNewImageCommand(new(searchService))
|
||||
|
@ -420,8 +420,8 @@ func TestSignature(t *testing.T) {
|
|||
So(err, ShouldBeNil)
|
||||
str = space.ReplaceAllString(buff.String(), " ")
|
||||
actual = strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 0.0.1 6742241d linux/amd64 true 447B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 0.0.1 linux/amd64 6742241d true 447B")
|
||||
|
||||
err = os.Chdir(currentWorkingDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -469,8 +469,8 @@ func TestDerivedImageList(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 2694fdb0 N/A false 824B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 2694fdb0 false 824B")
|
||||
})
|
||||
|
||||
Convey("Test derived images list fails", func() {
|
||||
|
@ -542,8 +542,8 @@ func TestBaseImageList(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 3fc80493 N/A false 494B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 3fc80493 false 494B")
|
||||
})
|
||||
|
||||
Convey("Test base images list fail", func() {
|
||||
|
@ -732,7 +732,7 @@ func TestOutputFormat(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
So(strings.TrimSpace(str), ShouldEqual,
|
||||
"IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE dummyImageName tag 6e2f80bf os/arch false 123kB")
|
||||
"IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE dummyImageName tag os/arch 6e2f80bf false 123kB")
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
|
@ -756,7 +756,8 @@ func TestOutputFormat(t *testing.T) {
|
|||
`"layers": [ { "size": "0", "digest": "sha256:c122a146f0d02349be211bb95cc2530f4a5793f96edbdfa00860f741e5d8c0e6" } ], `+ //nolint:lll
|
||||
`"platform": { "os": "os", "arch": "arch", "variant": "" }, `+
|
||||
`"size": "123445", "isSigned": false } ], `+
|
||||
`"size": "123445", "isSigned": false }`)
|
||||
`"size": "123445", "digest": "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", `+
|
||||
`"mediaType": "application/vnd.oci.image.manifest.v1+json", "isSigned": false }`)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
|
@ -782,7 +783,8 @@ func TestOutputFormat(t *testing.T) {
|
|||
`layers: - size: 0 digest: sha256:c122a146f0d02349be211bb95cc2530f4a5793f96edbdfa00860f741e5d8c0e6 `+
|
||||
`platform: os: os arch: arch variant: "" `+
|
||||
`size: "123445" issigned: false `+
|
||||
`size: "123445" issigned: false`,
|
||||
`size: "123445" digest: sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 `+
|
||||
`mediatype: application/vnd.oci.image.manifest.v1+json issigned: false`,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
|
@ -811,7 +813,8 @@ func TestOutputFormat(t *testing.T) {
|
|||
`layers: - size: 0 digest: sha256:c122a146f0d02349be211bb95cc2530f4a5793f96edbdfa00860f741e5d8c0e6 `+
|
||||
`platform: os: os arch: arch variant: "" `+
|
||||
`size: "123445" issigned: false `+
|
||||
`size: "123445" issigned: false`,
|
||||
`size: "123445" digest: sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 `+
|
||||
`mediatype: application/vnd.oci.image.manifest.v1+json issigned: false`,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
@ -867,9 +870,9 @@ func TestServerResponseGQL(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 linux/amd64 883fc0c5 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 883fc0c5 false 492B")
|
||||
Convey("Test all images invalid output format", func() {
|
||||
args := []string{"imagetest", "-o", "random"}
|
||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s","showspinner":false}]}`, url))
|
||||
|
@ -900,14 +903,14 @@ func TestServerResponseGQL(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// IMAGE NAME TAG DIGEST CONFIG OS/ARCH SIGNED LAYERS SIZE
|
||||
// repo7 test:2.0 a0ca253b b8781e88 linux/amd64 false 492B
|
||||
// b8781e88 15B
|
||||
// repo7 test:1.0 a0ca253b b8781e88 linux/amd64 false 492B
|
||||
// b8781e88 15B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST CONFIG OS/ARCH SIGNED LAYERS SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 3a1d2d0c linux/amd64 false 492B b8781e88 15B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 3a1d2d0c linux/amd64 false 492B b8781e88 15B")
|
||||
// IMAGE NAME TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE
|
||||
// repo7 test:2.0 linux/amd64 a0ca253b b8781e88 false 492B
|
||||
// b8781e88 15B
|
||||
// repo7 test:1.0 linux/amd64 a0ca253b b8781e88 false 492B
|
||||
// b8781e88 15B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 linux/amd64 883fc0c5 3a1d2d0c false 492B b8781e88 15B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 883fc0c5 3a1d2d0c false 492B b8781e88 15B")
|
||||
})
|
||||
|
||||
Convey("Test all images with debug flag", func() {
|
||||
|
@ -925,9 +928,9 @@ func TestServerResponseGQL(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "GET")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 linux/amd64 883fc0c5 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 883fc0c5 false 492B")
|
||||
})
|
||||
|
||||
Convey("Test image by name config url", func() {
|
||||
|
@ -944,9 +947,9 @@ func TestServerResponseGQL(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 linux/amd64 883fc0c5 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 883fc0c5 false 492B")
|
||||
|
||||
Convey("with shorthand", func() {
|
||||
args := []string{"imagetest", "-n", "repo7"}
|
||||
|
@ -962,9 +965,9 @@ func TestServerResponseGQL(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 linux/amd64 883fc0c5 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 883fc0c5 false 492B")
|
||||
})
|
||||
|
||||
Convey("invalid output format", func() {
|
||||
|
@ -997,12 +1000,12 @@ func TestServerResponseGQL(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// IMAGE NAME TAG DIGEST OS/ARCH SIZE
|
||||
// repo7 test:2.0 a0ca253b N/A 15B
|
||||
// repo7 test:1.0 a0ca253b N/A 15B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 N/A false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 N/A false 492B")
|
||||
// IMAGE NAME TAG OS/ARCH DIGEST SIZE
|
||||
// repo7 test:2.0 a0ca253b 15B
|
||||
// repo7 test:1.0 a0ca253b 15B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 false 492B")
|
||||
|
||||
Convey("with shorthand", func() {
|
||||
args := []string{"imagetest", "-d", "883fc0c5"}
|
||||
|
@ -1018,9 +1021,9 @@ func TestServerResponseGQL(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 N/A false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 N/A false 492B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 false 492B")
|
||||
})
|
||||
|
||||
Convey("nonexistent digest", func() {
|
||||
|
@ -1128,9 +1131,9 @@ func TestServerResponse(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 linux/amd64 883fc0c5 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 883fc0c5 false 492B")
|
||||
})
|
||||
|
||||
Convey("Test all images verbose", func() {
|
||||
|
@ -1148,14 +1151,14 @@ func TestServerResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// IMAGE NAME TAG DIGEST CONFIG OS/ARCH SIGNED LAYERS SIZE
|
||||
// repo7 test:2.0 a0ca253b b8781e88 linux/amd64 false 492B
|
||||
// linux/amd64 b8781e88 15B
|
||||
// repo7 test:1.0 a0ca253b b8781e88 linux/amd64 false 492B
|
||||
// linux/amd64 b8781e88 15B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST CONFIG OS/ARCH SIGNED LAYERS SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 3a1d2d0c linux/amd64 false 492B b8781e88 15B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 3a1d2d0c linux/amd64 false 492B b8781e88 15B")
|
||||
// IMAGE NAME TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE
|
||||
// repo7 test:2.0 linux/amd64 a0ca253b b8781e88 false 492B
|
||||
// b8781e88 15B
|
||||
// repo7 test:1.0 linux/amd64 a0ca253b b8781e88 false 492B
|
||||
// b8781e88 15B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 linux/amd64 883fc0c5 3a1d2d0c false 492B b8781e88 15B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 883fc0c5 3a1d2d0c false 492B b8781e88 15B")
|
||||
})
|
||||
|
||||
Convey("Test image by name", func() {
|
||||
|
@ -1172,9 +1175,9 @@ func TestServerResponse(t *testing.T) {
|
|||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 linux/amd64 883fc0c5 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 883fc0c5 false 492B")
|
||||
})
|
||||
|
||||
Convey("Test image by digest", func() {
|
||||
|
@ -1192,12 +1195,12 @@ func TestServerResponse(t *testing.T) {
|
|||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// IMAGE NAME TAG DIGEST OS/ARCH SIZE
|
||||
// repo7 test:2.0 a0ca253b linux/amd64 492B
|
||||
// repo7 test:1.0 a0ca253b linux/amd64 492B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG DIGEST OS/ARCH SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 883fc0c5 linux/amd64 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 883fc0c5 linux/amd64 false 492B")
|
||||
// IMAGE NAME TAG OS/ARCH DIGEST SIZE
|
||||
// repo7 test:2.0 linux/amd64 a0ca253b 492B
|
||||
// repo7 test:1.0 linux/amd64 a0ca253b 492B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:2.0 linux/amd64 883fc0c5 false 492B")
|
||||
So(actual, ShouldContainSubstring, "repo7 test:1.0 linux/amd64 883fc0c5 false 492B")
|
||||
|
||||
Convey("nonexistent digest", func() {
|
||||
args := []string{"imagetest", "--digest", "d1g35t"}
|
||||
|
@ -1269,6 +1272,153 @@ func TestServerResponseGQLWithoutPermissions(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestDisplayIndex(t *testing.T) {
|
||||
Convey("Init Basic Server, No GQL", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
|
||||
Convey("No GQL", func() {
|
||||
defaultVal := false
|
||||
conf.Extensions = &extconf.ExtensionConfig{
|
||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||
}
|
||||
ctlr := api.NewController(conf)
|
||||
ctlr.Config.Storage.RootDirectory = t.TempDir()
|
||||
cm := test.NewControllerManager(ctlr)
|
||||
|
||||
cm.StartAndWait(conf.HTTP.Port)
|
||||
defer cm.StopServer()
|
||||
|
||||
runDisplayIndexTests(baseURL)
|
||||
})
|
||||
|
||||
Convey("With GQL", func() {
|
||||
defaultVal := true
|
||||
conf.Extensions = &extconf.ExtensionConfig{
|
||||
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
|
||||
}
|
||||
ctlr := api.NewController(conf)
|
||||
ctlr.Config.Storage.RootDirectory = t.TempDir()
|
||||
cm := test.NewControllerManager(ctlr)
|
||||
|
||||
cm.StartAndWait(conf.HTTP.Port)
|
||||
defer cm.StopServer()
|
||||
|
||||
runDisplayIndexTests(baseURL)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func runDisplayIndexTests(baseURL string) {
|
||||
Convey("Test Image Index", func() {
|
||||
uploadTestMultiarch(baseURL)
|
||||
|
||||
args := []string{"imagetest"}
|
||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s","showspinner":false}]}`,
|
||||
baseURL))
|
||||
defer os.Remove(configPath)
|
||||
cmd := MockNewImageCommand(new(searchService))
|
||||
buff := bytes.NewBufferString("")
|
||||
cmd.SetOut(buff)
|
||||
cmd.SetErr(buff)
|
||||
cmd.SetArgs(args)
|
||||
err := cmd.Execute()
|
||||
So(err, ShouldBeNil)
|
||||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE
|
||||
// repo multi-arch * 46b78b06 false 1.4kB
|
||||
// linux/amd64 97b0d65c false 577B
|
||||
// windows/arm64/v6 dcfa3a9c false 444B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 46b78b06 false 1.4kB ")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 97b0d65c false 577B ")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 dcfa3a9c false 444B")
|
||||
})
|
||||
|
||||
Convey("Test Image Index Verbose", func() {
|
||||
uploadTestMultiarch(baseURL)
|
||||
|
||||
args := []string{"imagetest", "--verbose"}
|
||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"imagetest","url":"%s","showspinner":false}]}`,
|
||||
baseURL))
|
||||
defer os.Remove(configPath)
|
||||
cmd := MockNewImageCommand(new(searchService))
|
||||
buff := bytes.NewBufferString("")
|
||||
cmd.SetOut(buff)
|
||||
cmd.SetErr(buff)
|
||||
cmd.SetArgs(args)
|
||||
err := cmd.Execute()
|
||||
So(err, ShouldBeNil)
|
||||
space := regexp.MustCompile(`\s+`)
|
||||
str := space.ReplaceAllString(buff.String(), " ")
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// IMAGE NAME TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE
|
||||
// repo multi-arch * 46b78b06 false 1.4kB
|
||||
// linux/amd64 97b0d65c 58cc9abe false 577B
|
||||
// cbb5b121 4B
|
||||
// a00291e8 4B
|
||||
// windows/arm64/v6 dcfa3a9c 5132a1cd false 444B
|
||||
// 7d08ce29 4B
|
||||
So(actual, ShouldContainSubstring, "IMAGE NAME TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 46b78b06 false 1.4kB")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 97b0d65c 58cc9abe false 577B")
|
||||
So(actual, ShouldContainSubstring, "cbb5b121 4B")
|
||||
So(actual, ShouldContainSubstring, "a00291e8 4B")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 dcfa3a9c 5132a1cd false 444B")
|
||||
So(actual, ShouldContainSubstring, "7d08ce29 4B")
|
||||
})
|
||||
}
|
||||
|
||||
func uploadTestMultiarch(baseURL string) {
|
||||
// ------- Define Image1
|
||||
layer11 := []byte{11, 12, 13, 14}
|
||||
layer12 := []byte{16, 17, 18, 19}
|
||||
|
||||
image1, err := test.GetImageWithComponents(
|
||||
ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
OS: "linux",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
},
|
||||
[][]byte{
|
||||
layer11,
|
||||
layer12,
|
||||
},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// ------ Define Image2
|
||||
layer21 := []byte{21, 22, 23, 24}
|
||||
|
||||
image2, err := test.GetImageWithComponents(
|
||||
ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
OS: "windows",
|
||||
Architecture: "arm64",
|
||||
Variant: "v6",
|
||||
},
|
||||
},
|
||||
[][]byte{
|
||||
layer21,
|
||||
},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// ------- Upload The multiarch image
|
||||
|
||||
multiarch := test.GetMultiarchImageForImages("multi-arch", []test.Image{image1, image2})
|
||||
|
||||
err = test.UploadMultiarchImage(multiarch, baseURL, "repo")
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
|
||||
func MockNewImageCommand(searchService SearchService) *cobra.Command {
|
||||
searchImageParams := make(map[string]*string)
|
||||
|
||||
|
@ -1596,8 +1746,10 @@ func (service mockService) getImagesGQL(ctx context.Context, config searchConfig
|
|||
imageListGQLResponse := &imageListStructGQL{}
|
||||
imageListGQLResponse.Data.Results = []imageStruct{
|
||||
{
|
||||
RepoName: "dummyImageName",
|
||||
Tag: "tag",
|
||||
RepoName: "dummyImageName",
|
||||
Tag: "tag",
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: godigest.FromString("test").String(),
|
||||
Manifests: []manifestStruct{
|
||||
{
|
||||
Digest: godigest.FromString("Digest").String(),
|
||||
|
@ -1619,8 +1771,10 @@ func (service mockService) getImagesByDigestGQL(ctx context.Context, config sear
|
|||
imageListGQLResponse := &imageListStructForDigestGQL{}
|
||||
imageListGQLResponse.Data.Results = []imageStruct{
|
||||
{
|
||||
RepoName: "randomimageName",
|
||||
Tag: "tag",
|
||||
RepoName: "randomimageName",
|
||||
Tag: "tag",
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: godigest.FromString("test").String(),
|
||||
Manifests: []manifestStruct{
|
||||
{
|
||||
Digest: godigest.FromString("Digest").String(),
|
||||
|
@ -1745,6 +1899,8 @@ func (service mockService) getAllImages(ctx context.Context, config searchConfig
|
|||
image := &imageStruct{}
|
||||
image.RepoName = "randomimageName"
|
||||
image.Tag = "tag"
|
||||
image.Digest = godigest.FromString("test").String()
|
||||
image.MediaType = ispec.MediaTypeImageManifest
|
||||
image.Manifests = []manifestStruct{
|
||||
{
|
||||
Digest: godigest.FromString("Digest").String(),
|
||||
|
@ -1775,6 +1931,8 @@ func (service mockService) getImageByName(ctx context.Context, config searchConf
|
|||
image := &imageStruct{}
|
||||
image.RepoName = imageName
|
||||
image.Tag = "tag"
|
||||
image.Digest = godigest.FromString("test").String()
|
||||
image.MediaType = ispec.MediaTypeImageManifest
|
||||
image.Manifests = []manifestStruct{
|
||||
{
|
||||
Digest: godigest.FromString("Digest").String(),
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
zotErrors "zotregistry.io/zot/errors"
|
||||
|
@ -74,11 +75,14 @@ func (service searchService) getDerivedImageListGQL(ctx context.Context, config
|
|||
Results{
|
||||
RepoName,
|
||||
Tag,
|
||||
Digest,
|
||||
MediaType,
|
||||
Manifests {
|
||||
Digest,
|
||||
ConfigDigest,
|
||||
Layers {Size Digest},
|
||||
LastUpdated,
|
||||
IsSigned,
|
||||
Size
|
||||
},
|
||||
LastUpdated,
|
||||
|
@ -107,11 +111,14 @@ func (service searchService) getBaseImageListGQL(ctx context.Context, config sea
|
|||
Results{
|
||||
RepoName,
|
||||
Tag,
|
||||
Digest,
|
||||
MediaType,
|
||||
Manifests {
|
||||
Digest,
|
||||
ConfigDigest,
|
||||
Layers {Size Digest},
|
||||
LastUpdated,
|
||||
IsSigned,
|
||||
Size
|
||||
},
|
||||
LastUpdated,
|
||||
|
@ -139,11 +146,14 @@ func (service searchService) getImagesGQL(ctx context.Context, config searchConf
|
|||
ImageList(repo: "%s") {
|
||||
Results {
|
||||
RepoName Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
Size
|
||||
Platform {Os Arch}
|
||||
IsSigned
|
||||
Layers {Size Digest}
|
||||
}
|
||||
Size
|
||||
|
@ -171,12 +181,15 @@ func (service searchService) getImagesByDigestGQL(ctx context.Context, config se
|
|||
ImageListForDigest(id: "%s") {
|
||||
Results {
|
||||
RepoName Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
Size
|
||||
IsSigned
|
||||
Layers {Size Digest}
|
||||
}
|
||||
}
|
||||
Size
|
||||
IsSigned
|
||||
}
|
||||
|
@ -202,12 +215,15 @@ func (service searchService) getImagesByCveIDGQL(ctx context.Context, config sea
|
|||
ImageListForCVE(id: "%s") {
|
||||
Results {
|
||||
RepoName Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
Size
|
||||
IsSigned
|
||||
Layers {Size Digest}
|
||||
}
|
||||
}
|
||||
Size
|
||||
IsSigned
|
||||
}
|
||||
|
@ -252,10 +268,13 @@ func (service searchService) getTagsForCVEGQL(ctx context.Context, config search
|
|||
ImageListForCVE(id: "%s") {
|
||||
Results {
|
||||
RepoName Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
Size
|
||||
IsSigned
|
||||
Layers {Size Digest}
|
||||
}
|
||||
Size
|
||||
|
@ -282,12 +301,15 @@ func (service searchService) getFixedTagsForCVEGQL(ctx context.Context, config s
|
|||
ImageListWithCVEFixed(id: "%s", image: "%s") {
|
||||
Results {
|
||||
RepoName Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
Size
|
||||
IsSigned
|
||||
Layers {Size Digest}
|
||||
}
|
||||
}
|
||||
Size
|
||||
}
|
||||
}
|
||||
|
@ -426,12 +448,15 @@ func (service searchService) getImagesByCveID(ctx context.Context, config search
|
|||
ImageListForCVE(id: "%s") {
|
||||
Results {
|
||||
RepoName Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
Size
|
||||
IsSigned
|
||||
Layers {Size Digest}
|
||||
}
|
||||
}
|
||||
Size
|
||||
}
|
||||
}
|
||||
|
@ -492,12 +517,15 @@ func (service searchService) getImagesByDigest(ctx context.Context, config searc
|
|||
ImageListForDigest(id: "%s") {
|
||||
Results {
|
||||
RepoName Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
Size
|
||||
IsSigned
|
||||
Layers {Size Digest}
|
||||
}
|
||||
}
|
||||
Size
|
||||
}
|
||||
}
|
||||
|
@ -558,12 +586,15 @@ func (service searchService) getImageByNameAndCVEID(ctx context.Context, config
|
|||
ImageListForCVE(id: "%s") {
|
||||
Results {
|
||||
RepoName Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
Size
|
||||
IsSigned
|
||||
Layers {Size Digest}
|
||||
}
|
||||
}
|
||||
Size
|
||||
}
|
||||
}
|
||||
|
@ -682,12 +713,15 @@ func (service searchService) getFixedTagsForCVE(ctx context.Context, config sear
|
|||
ImageListWithCVEFixed (id: "%s", image: "%s") {
|
||||
Results {
|
||||
RepoName Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
Size
|
||||
IsSigned
|
||||
Layers {Size Digest}
|
||||
}
|
||||
}
|
||||
Size
|
||||
}
|
||||
}
|
||||
|
@ -984,8 +1018,10 @@ type imageStruct struct {
|
|||
Tag string `json:"tag"`
|
||||
Manifests []manifestStruct
|
||||
Size string `json:"size"`
|
||||
Digest string `json:"digest"`
|
||||
MediaType string `json:"mediaType"`
|
||||
IsSigned bool `json:"isSigned"`
|
||||
verbose bool
|
||||
IsSigned bool `json:"isSigned"`
|
||||
}
|
||||
|
||||
type manifestStruct struct {
|
||||
|
@ -1106,69 +1142,9 @@ func (img imageStruct) stringPlainText(maxImgNameLen, maxTagLen, maxPlatformLen
|
|||
tagName += offset
|
||||
}
|
||||
|
||||
for i := range img.Manifests {
|
||||
manifestDigest, err := godigest.Parse(img.Manifests[i].Digest)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error parsing manifest digest %s: %w", img.Manifests[i].Digest, err)
|
||||
}
|
||||
|
||||
configDigest, err := godigest.Parse(img.Manifests[i].ConfigDigest)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error parsing config digest %s: %w", img.Manifests[i].ConfigDigest, err)
|
||||
}
|
||||
|
||||
platform := getPlatformStr(img.Manifests[i].Platform)
|
||||
|
||||
if maxPlatformLen > len(platform) {
|
||||
offset = strings.Repeat(" ", maxPlatformLen-len(platform))
|
||||
platform += offset
|
||||
}
|
||||
|
||||
minifestDigestStr := ellipsize(manifestDigest.Encoded(), digestWidth, "")
|
||||
configDigestStr := ellipsize(configDigest.Encoded(), configWidth, "")
|
||||
imgSize, _ := strconv.ParseUint(img.Manifests[i].Size, 10, 64)
|
||||
size := ellipsize(strings.ReplaceAll(humanize.Bytes(imgSize), " ", ""), sizeWidth, ellipsis)
|
||||
isSigned := img.IsSigned
|
||||
row := make([]string, 8) //nolint:gomnd
|
||||
|
||||
row[colImageNameIndex] = imageName
|
||||
row[colTagIndex] = tagName
|
||||
row[colDigestIndex] = minifestDigestStr
|
||||
row[colPlatformIndex] = platform
|
||||
row[colSizeIndex] = size
|
||||
row[colIsSignedIndex] = strconv.FormatBool(isSigned)
|
||||
|
||||
if img.verbose {
|
||||
row[colConfigIndex] = configDigestStr
|
||||
row[colLayersIndex] = ""
|
||||
}
|
||||
|
||||
table.Append(row)
|
||||
|
||||
if img.verbose {
|
||||
for _, entry := range img.Manifests[i].Layers {
|
||||
layerSize := entry.Size
|
||||
size := ellipsize(strings.ReplaceAll(humanize.Bytes(uint64(layerSize)), " ", ""), sizeWidth, ellipsis)
|
||||
|
||||
layerDigest, err := godigest.Parse(entry.Digest)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error parsing layer digest %s: %w", entry.Digest, err)
|
||||
}
|
||||
|
||||
layerDigestStr := ellipsize(layerDigest.Encoded(), digestWidth, "")
|
||||
|
||||
layerRow := make([]string, 8) //nolint:gomnd
|
||||
layerRow[colImageNameIndex] = ""
|
||||
layerRow[colTagIndex] = ""
|
||||
layerRow[colDigestIndex] = ""
|
||||
layerRow[colPlatformIndex] = ""
|
||||
layerRow[colSizeIndex] = size
|
||||
layerRow[colConfigIndex] = ""
|
||||
layerRow[colLayersIndex] = layerDigestStr
|
||||
|
||||
table.Append(layerRow)
|
||||
}
|
||||
}
|
||||
err := addImageToTable(table, &img, maxPlatformLen, imageName, tagName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
table.Render()
|
||||
|
@ -1176,9 +1152,125 @@ func (img imageStruct) stringPlainText(maxImgNameLen, maxTagLen, maxPlatformLen
|
|||
return builder.String(), nil
|
||||
}
|
||||
|
||||
func addImageToTable(table *tablewriter.Table, img *imageStruct, maxPlatformLen int,
|
||||
imageName, tagName string,
|
||||
) error {
|
||||
switch img.MediaType {
|
||||
case ispec.MediaTypeImageManifest:
|
||||
return addManifestToTable(table, imageName, tagName, &img.Manifests[0], maxPlatformLen, img.verbose)
|
||||
case ispec.MediaTypeImageIndex:
|
||||
return addImageIndexToTable(table, img, maxPlatformLen, imageName, tagName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addImageIndexToTable(table *tablewriter.Table, img *imageStruct, maxPlatformLen int,
|
||||
imageName, tagName string,
|
||||
) error {
|
||||
indexDigest, err := godigest.Parse(img.Digest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing index digest %s: %w", indexDigest, err)
|
||||
}
|
||||
row := make([]string, rowWidth)
|
||||
row[colImageNameIndex] = imageName
|
||||
row[colTagIndex] = tagName
|
||||
row[colDigestIndex] = ellipsize(indexDigest.Encoded(), digestWidth, "")
|
||||
row[colPlatformIndex] = "*"
|
||||
|
||||
imgSize, _ := strconv.ParseUint(img.Size, 10, 64)
|
||||
row[colSizeIndex] = ellipsize(strings.ReplaceAll(humanize.Bytes(imgSize), " ", ""), sizeWidth, ellipsis)
|
||||
row[colIsSignedIndex] = strconv.FormatBool(img.IsSigned)
|
||||
|
||||
if img.verbose {
|
||||
row[colConfigIndex] = ""
|
||||
row[colLayersIndex] = ""
|
||||
}
|
||||
|
||||
table.Append(row)
|
||||
|
||||
for i := range img.Manifests {
|
||||
err := addManifestToTable(table, "", "", &img.Manifests[i], maxPlatformLen, img.verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func addManifestToTable(table *tablewriter.Table, imageName, tagName string, manifest *manifestStruct,
|
||||
maxPlatformLen int, verbose bool,
|
||||
) error {
|
||||
manifestDigest, err := godigest.Parse(manifest.Digest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing manifest digest %s: %w", manifest.Digest, err)
|
||||
}
|
||||
|
||||
configDigest, err := godigest.Parse(manifest.ConfigDigest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing config digest %s: %w", manifest.ConfigDigest, err)
|
||||
}
|
||||
|
||||
platform := getPlatformStr(manifest.Platform)
|
||||
|
||||
if maxPlatformLen > len(platform) {
|
||||
offset := strings.Repeat(" ", maxPlatformLen-len(platform))
|
||||
platform += offset
|
||||
}
|
||||
|
||||
minifestDigestStr := ellipsize(manifestDigest.Encoded(), digestWidth, "")
|
||||
configDigestStr := ellipsize(configDigest.Encoded(), configWidth, "")
|
||||
imgSize, _ := strconv.ParseUint(manifest.Size, 10, 64)
|
||||
size := ellipsize(strings.ReplaceAll(humanize.Bytes(imgSize), " ", ""), sizeWidth, ellipsis)
|
||||
isSigned := manifest.IsSigned
|
||||
row := make([]string, 8) //nolint:gomnd
|
||||
|
||||
row[colImageNameIndex] = imageName
|
||||
row[colTagIndex] = tagName
|
||||
row[colDigestIndex] = minifestDigestStr
|
||||
row[colPlatformIndex] = platform
|
||||
row[colSizeIndex] = size
|
||||
row[colIsSignedIndex] = strconv.FormatBool(isSigned)
|
||||
|
||||
if verbose {
|
||||
row[colConfigIndex] = configDigestStr
|
||||
row[colLayersIndex] = ""
|
||||
}
|
||||
|
||||
table.Append(row)
|
||||
|
||||
if verbose {
|
||||
for _, entry := range manifest.Layers {
|
||||
layerSize := entry.Size
|
||||
size := ellipsize(strings.ReplaceAll(humanize.Bytes(uint64(layerSize)), " ", ""), sizeWidth, ellipsis)
|
||||
|
||||
layerDigest, err := godigest.Parse(entry.Digest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing layer digest %s: %w", entry.Digest, err)
|
||||
}
|
||||
|
||||
layerDigestStr := ellipsize(layerDigest.Encoded(), digestWidth, "")
|
||||
|
||||
layerRow := make([]string, 8) //nolint:gomnd
|
||||
layerRow[colImageNameIndex] = ""
|
||||
layerRow[colTagIndex] = ""
|
||||
layerRow[colDigestIndex] = ""
|
||||
layerRow[colPlatformIndex] = ""
|
||||
layerRow[colSizeIndex] = size
|
||||
layerRow[colConfigIndex] = ""
|
||||
layerRow[colLayersIndex] = layerDigestStr
|
||||
|
||||
table.Append(layerRow)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPlatformStr(platf platform) string {
|
||||
if platf.Arch == "" && platf.Os == "" {
|
||||
return "N/A"
|
||||
return ""
|
||||
}
|
||||
|
||||
platform := platf.Os
|
||||
|
@ -1332,15 +1424,6 @@ const (
|
|||
layersWidth = 8
|
||||
ellipsis = "..."
|
||||
|
||||
colImageNameIndex = 0
|
||||
colTagIndex = 1
|
||||
colDigestIndex = 2
|
||||
colConfigIndex = 3
|
||||
colPlatformIndex = 4
|
||||
colIsSignedIndex = 5
|
||||
colLayersIndex = 6
|
||||
colSizeIndex = 7
|
||||
|
||||
cveIDWidth = 16
|
||||
cveSeverityWidth = 8
|
||||
cveTitleWidth = 48
|
||||
|
@ -1351,3 +1434,16 @@ const (
|
|||
|
||||
defaultOutoutFormat = "text"
|
||||
)
|
||||
|
||||
const (
|
||||
colImageNameIndex = iota
|
||||
colTagIndex
|
||||
colPlatformIndex
|
||||
colDigestIndex
|
||||
colConfigIndex
|
||||
colIsSignedIndex
|
||||
colLayersIndex
|
||||
colSizeIndex
|
||||
|
||||
rowWidth
|
||||
)
|
||||
|
|
|
@ -6544,6 +6544,8 @@ func TestImageSummary(t *testing.T) {
|
|||
Image(image:"%s:%s"){
|
||||
RepoName
|
||||
Tag
|
||||
Digest
|
||||
MediaType
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
|
@ -6569,6 +6571,8 @@ func TestImageSummary(t *testing.T) {
|
|||
Image(image:"%s"){
|
||||
RepoName,
|
||||
Tag,
|
||||
Digest,
|
||||
MediaType,
|
||||
Manifests {
|
||||
Digest
|
||||
ConfigDigest
|
||||
|
@ -6679,6 +6683,8 @@ func TestImageSummary(t *testing.T) {
|
|||
imgSummary := imgSummaryResponse.SingleImageSummary.ImageSummary
|
||||
So(imgSummary.RepoName, ShouldContainSubstring, repoName)
|
||||
So(imgSummary.Tag, ShouldContainSubstring, tagTarget)
|
||||
So(imgSummary.Digest, ShouldContainSubstring, manifestDigest.Encoded())
|
||||
So(imgSummary.MediaType, ShouldContainSubstring, ispec.MediaTypeImageManifest)
|
||||
So(imgSummary.Manifests[0].ConfigDigest, ShouldContainSubstring, image.Manifest.Config.Digest.Encoded())
|
||||
So(imgSummary.Manifests[0].Digest, ShouldContainSubstring, manifestDigest.Encoded())
|
||||
So(len(imgSummary.Manifests[0].Layers), ShouldEqual, 1)
|
||||
|
|
|
@ -22,6 +22,8 @@ type RepoSummary struct {
|
|||
type ImageSummary struct {
|
||||
RepoName string `json:"repoName"`
|
||||
Tag string `json:"tag"`
|
||||
Digest string `json:"digest"`
|
||||
MediaType string `json:"mediaType"`
|
||||
Manifests []ManifestSummary `json:"manifests"`
|
||||
Size string `json:"size"`
|
||||
DownloadCount int `json:"downloadCount"`
|
||||
|
|
|
@ -132,8 +132,16 @@ func TestConvertErrors(t *testing.T) {
|
|||
Convey("ImageManifest2ImageSummary", t, func() {
|
||||
ctx := graphql.WithResponseContext(context.Background(),
|
||||
graphql.DefaultErrorPresenter, graphql.DefaultRecover)
|
||||
configBlob, err := json.Marshal(ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
OS: "os",
|
||||
Architecture: "arch",
|
||||
Variant: "var",
|
||||
},
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
_, _, err := convert.ImageManifest2ImageSummary(
|
||||
_, _, err = convert.ImageManifest2ImageSummary(
|
||||
ctx,
|
||||
"repo",
|
||||
"tag",
|
||||
|
@ -142,7 +150,7 @@ func TestConvertErrors(t *testing.T) {
|
|||
repodb.RepoMetadata{},
|
||||
repodb.ManifestMetadata{
|
||||
ManifestBlob: []byte("{}"),
|
||||
ConfigBlob: []byte("{}"),
|
||||
ConfigBlob: configBlob,
|
||||
},
|
||||
mocks.CveInfoMock{
|
||||
GetCVESummaryForImageFn: func(repo, reference string,
|
||||
|
@ -168,6 +176,12 @@ func TestConvertErrors(t *testing.T) {
|
|||
MediaType: ispec.MediaTypeImageManifest,
|
||||
},
|
||||
false,
|
||||
repodb.RepoMetadata{
|
||||
Tags: map[string]repodb.Descriptor{},
|
||||
Statistics: map[string]repodb.DescriptorStatistics{},
|
||||
Signatures: map[string]repodb.ManifestSignatures{},
|
||||
Referrers: map[string][]repodb.ReferrerInfo{},
|
||||
},
|
||||
repodb.ManifestMetadata{
|
||||
ManifestBlob: []byte("{}"),
|
||||
ConfigBlob: []byte("bad json"),
|
||||
|
@ -187,6 +201,7 @@ func TestConvertErrors(t *testing.T) {
|
|||
Platform: ispec.Platform{
|
||||
OS: "os",
|
||||
Architecture: "arch",
|
||||
Variant: "var",
|
||||
},
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -200,6 +215,12 @@ func TestConvertErrors(t *testing.T) {
|
|||
MediaType: ispec.MediaTypeImageManifest,
|
||||
},
|
||||
false,
|
||||
repodb.RepoMetadata{
|
||||
Tags: map[string]repodb.Descriptor{},
|
||||
Statistics: map[string]repodb.DescriptorStatistics{},
|
||||
Signatures: map[string]repodb.ManifestSignatures{"dig": {"cosine": []repodb.SignatureInfo{{}}}},
|
||||
Referrers: map[string][]repodb.ReferrerInfo{},
|
||||
},
|
||||
repodb.ManifestMetadata{
|
||||
ManifestBlob: []byte("{}"),
|
||||
ConfigBlob: configBlob,
|
||||
|
@ -245,6 +266,33 @@ func TestConvertErrors(t *testing.T) {
|
|||
}, log.NewLogger("debug", ""),
|
||||
)
|
||||
So(len(imageSummaries), ShouldEqual, 0)
|
||||
|
||||
// cveInfo present no error
|
||||
_, imageSummaries = convert.RepoMeta2ExpandedRepoInfo(
|
||||
ctx,
|
||||
repodb.RepoMetadata{
|
||||
Tags: map[string]repodb.Descriptor{
|
||||
"tag1": {Digest: "dig", MediaType: ispec.MediaTypeImageManifest},
|
||||
},
|
||||
},
|
||||
map[string]repodb.ManifestMetadata{
|
||||
"dig": {
|
||||
ManifestBlob: []byte("{}"),
|
||||
ConfigBlob: []byte("{}"),
|
||||
},
|
||||
},
|
||||
map[string]repodb.IndexData{},
|
||||
convert.SkipQGLField{
|
||||
Vulnerabilities: false,
|
||||
},
|
||||
mocks.CveInfoMock{
|
||||
GetCVESummaryForImageFn: func(repo, reference string,
|
||||
) (cveinfo.ImageCVESummary, error) {
|
||||
return cveinfo.ImageCVESummary{}, ErrTestError
|
||||
},
|
||||
}, log.NewLogger("debug", ""),
|
||||
)
|
||||
So(len(imageSummaries), ShouldEqual, 1)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -189,11 +189,14 @@ func ImageIndex2ImageSummary(ctx context.Context, repo, tag string, indexDigest
|
|||
maxSeverity string
|
||||
manifestSummaries = make([]*gql_generated.ManifestSummary, 0, len(indexContent.Manifests))
|
||||
indexBlobs = make(map[string]int64, 0)
|
||||
|
||||
indexDigestStr = indexDigest.String()
|
||||
indexMediaType = ispec.MediaTypeImageIndex
|
||||
)
|
||||
|
||||
for _, descriptor := range indexContent.Manifests {
|
||||
manifestSummary, manifestBlobs, err := ImageManifest2ManifestSummary(ctx, repo, tag, descriptor, false,
|
||||
manifestMetaMap[descriptor.Digest.String()], repoMeta.Referrers[descriptor.Digest.String()], cveInfo)
|
||||
repoMeta, manifestMetaMap[descriptor.Digest.String()], repoMeta.Referrers[descriptor.Digest.String()], cveInfo)
|
||||
if err != nil {
|
||||
return &gql_generated.ImageSummary{}, map[string]int64{}, err
|
||||
}
|
||||
|
@ -244,6 +247,8 @@ func ImageIndex2ImageSummary(ctx context.Context, repo, tag string, indexDigest
|
|||
indexSummary := gql_generated.ImageSummary{
|
||||
RepoName: &repo,
|
||||
Tag: &tag,
|
||||
Digest: &indexDigestStr,
|
||||
MediaType: &indexMediaType,
|
||||
Manifests: manifestSummaries,
|
||||
LastUpdated: &indexLastUpdated,
|
||||
IsSigned: &isSigned,
|
||||
|
@ -272,6 +277,7 @@ func ImageManifest2ImageSummary(ctx context.Context, repo, tag string, digest go
|
|||
var (
|
||||
manifestContent ispec.Manifest
|
||||
manifestDigest = digest.String()
|
||||
mediaType = ispec.MediaTypeImageManifest
|
||||
)
|
||||
|
||||
err := json.Unmarshal(manifestMeta.ManifestBlob, &manifestContent)
|
||||
|
@ -349,14 +355,17 @@ func ImageManifest2ImageSummary(ctx context.Context, repo, tag string, digest go
|
|||
}
|
||||
|
||||
imageSummary := gql_generated.ImageSummary{
|
||||
RepoName: &repoName,
|
||||
Tag: &tag,
|
||||
RepoName: &repoName,
|
||||
Tag: &tag,
|
||||
Digest: &manifestDigest,
|
||||
MediaType: &mediaType,
|
||||
Manifests: []*gql_generated.ManifestSummary{
|
||||
{
|
||||
Digest: &manifestDigest,
|
||||
ConfigDigest: &configDigest,
|
||||
LastUpdated: &imageLastUpdated,
|
||||
Size: &imageSize,
|
||||
IsSigned: &isSigned,
|
||||
Platform: &platform,
|
||||
DownloadCount: &downloadCount,
|
||||
Layers: getLayersSummaries(manifestContent),
|
||||
|
@ -424,7 +433,8 @@ func getAnnotationsFromMap(annotationsMap map[string]string) []*gql_generated.An
|
|||
}
|
||||
|
||||
func ImageManifest2ManifestSummary(ctx context.Context, repo, tag string, descriptor ispec.Descriptor,
|
||||
skipCVE bool, manifestMeta repodb.ManifestMetadata, referrersInfo []repodb.ReferrerInfo, cveInfo cveinfo.CveInfo,
|
||||
skipCVE bool, repoMeta repodb.RepoMetadata, manifestMeta repodb.ManifestMetadata, referrersInfo []repodb.ReferrerInfo,
|
||||
cveInfo cveinfo.CveInfo,
|
||||
) (*gql_generated.ManifestSummary, map[string]int64, error) {
|
||||
var (
|
||||
manifestContent ispec.Manifest
|
||||
|
@ -456,6 +466,7 @@ func ImageManifest2ManifestSummary(ctx context.Context, repo, tag string, descri
|
|||
configSize = manifestContent.Config.Size
|
||||
imageLastUpdated = common.GetImageLastUpdated(configContent)
|
||||
downloadCount = manifestMeta.DownloadCount
|
||||
isSigned = false
|
||||
)
|
||||
|
||||
opSys := configContent.OS
|
||||
|
@ -492,6 +503,12 @@ func ImageManifest2ManifestSummary(ctx context.Context, repo, tag string, descri
|
|||
}
|
||||
}
|
||||
|
||||
for _, signatures := range repoMeta.Signatures[manifestDigestStr] {
|
||||
if len(signatures) > 0 {
|
||||
isSigned = true
|
||||
}
|
||||
}
|
||||
|
||||
manifestSummary := gql_generated.ManifestSummary{
|
||||
Digest: &manifestDigestStr,
|
||||
ConfigDigest: &configDigest,
|
||||
|
@ -501,6 +518,7 @@ func ImageManifest2ManifestSummary(ctx context.Context, repo, tag string, descri
|
|||
DownloadCount: &downloadCount,
|
||||
Layers: getLayersSummaries(manifestContent),
|
||||
History: historyEntries,
|
||||
IsSigned: &isSigned,
|
||||
Vulnerabilities: &gql_generated.ImageVulnerabilitySummary{
|
||||
MaxSeverity: &imageCveSummary.MaxSeverity,
|
||||
Count: &imageCveSummary.Count,
|
||||
|
|
|
@ -79,6 +79,7 @@ type ComplexityRoot struct {
|
|||
ImageSummary struct {
|
||||
Authors func(childComplexity int) int
|
||||
Description func(childComplexity int) int
|
||||
Digest func(childComplexity int) int
|
||||
Documentation func(childComplexity int) int
|
||||
DownloadCount func(childComplexity int) int
|
||||
IsSigned func(childComplexity int) int
|
||||
|
@ -86,6 +87,7 @@ type ComplexityRoot struct {
|
|||
LastUpdated func(childComplexity int) int
|
||||
Licenses func(childComplexity int) int
|
||||
Manifests func(childComplexity int) int
|
||||
MediaType func(childComplexity int) int
|
||||
Referrers func(childComplexity int) int
|
||||
RepoName func(childComplexity int) int
|
||||
Score func(childComplexity int) int
|
||||
|
@ -118,6 +120,7 @@ type ComplexityRoot struct {
|
|||
Digest func(childComplexity int) int
|
||||
DownloadCount func(childComplexity int) int
|
||||
History func(childComplexity int) int
|
||||
IsSigned func(childComplexity int) int
|
||||
LastUpdated func(childComplexity int) int
|
||||
Layers func(childComplexity int) int
|
||||
Platform func(childComplexity int) int
|
||||
|
@ -372,6 +375,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.ImageSummary.Description(childComplexity), true
|
||||
|
||||
case "ImageSummary.Digest":
|
||||
if e.complexity.ImageSummary.Digest == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.ImageSummary.Digest(childComplexity), true
|
||||
|
||||
case "ImageSummary.Documentation":
|
||||
if e.complexity.ImageSummary.Documentation == nil {
|
||||
break
|
||||
|
@ -421,6 +431,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.ImageSummary.Manifests(childComplexity), true
|
||||
|
||||
case "ImageSummary.MediaType":
|
||||
if e.complexity.ImageSummary.MediaType == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.ImageSummary.MediaType(childComplexity), true
|
||||
|
||||
case "ImageSummary.Referrers":
|
||||
if e.complexity.ImageSummary.Referrers == nil {
|
||||
break
|
||||
|
@ -561,6 +578,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||
|
||||
return e.complexity.ManifestSummary.History(childComplexity), true
|
||||
|
||||
case "ManifestSummary.IsSigned":
|
||||
if e.complexity.ManifestSummary.IsSigned == nil {
|
||||
break
|
||||
}
|
||||
|
||||
return e.complexity.ManifestSummary.IsSigned(childComplexity), true
|
||||
|
||||
case "ManifestSummary.LastUpdated":
|
||||
if e.complexity.ManifestSummary.LastUpdated == nil {
|
||||
break
|
||||
|
@ -1131,6 +1155,14 @@ type ImageSummary {
|
|||
"""
|
||||
Tag: String
|
||||
"""
|
||||
The digest of the descriptor of this image
|
||||
"""
|
||||
Digest: String
|
||||
"""
|
||||
The media type of the descriptor of this image
|
||||
"""
|
||||
MediaType: String
|
||||
"""
|
||||
List of manifests for all supported versions of the image for different operating systems and architectures
|
||||
"""
|
||||
Manifests: [ManifestSummary]
|
||||
|
@ -1217,6 +1249,10 @@ type ManifestSummary {
|
|||
"""
|
||||
Size: String
|
||||
"""
|
||||
True if the manifest has a signature associated with it, false otherwise
|
||||
"""
|
||||
IsSigned: Boolean
|
||||
"""
|
||||
OS and architecture supported by this image
|
||||
"""
|
||||
Platform: Platform
|
||||
|
@ -2587,6 +2623,10 @@ func (ec *executionContext) fieldContext_GlobalSearchResult_Images(ctx context.C
|
|||
return ec.fieldContext_ImageSummary_RepoName(ctx, field)
|
||||
case "Tag":
|
||||
return ec.fieldContext_ImageSummary_Tag(ctx, field)
|
||||
case "Digest":
|
||||
return ec.fieldContext_ImageSummary_Digest(ctx, field)
|
||||
case "MediaType":
|
||||
return ec.fieldContext_ImageSummary_MediaType(ctx, field)
|
||||
case "Manifests":
|
||||
return ec.fieldContext_ImageSummary_Manifests(ctx, field)
|
||||
case "Size":
|
||||
|
@ -3027,6 +3067,88 @@ func (ec *executionContext) fieldContext_ImageSummary_Tag(ctx context.Context, f
|
|||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ImageSummary_Digest(ctx context.Context, field graphql.CollectedField, obj *ImageSummary) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ImageSummary_Digest(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.Digest, 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_ImageSummary_Digest(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "ImageSummary",
|
||||
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) _ImageSummary_MediaType(ctx context.Context, field graphql.CollectedField, obj *ImageSummary) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ImageSummary_MediaType(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.MediaType, 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_ImageSummary_MediaType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||
fc = &graphql.FieldContext{
|
||||
Object: "ImageSummary",
|
||||
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) _ImageSummary_Manifests(ctx context.Context, field graphql.CollectedField, obj *ImageSummary) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ImageSummary_Manifests(ctx, field)
|
||||
if err != nil {
|
||||
|
@ -3071,6 +3193,8 @@ func (ec *executionContext) fieldContext_ImageSummary_Manifests(ctx context.Cont
|
|||
return ec.fieldContext_ManifestSummary_LastUpdated(ctx, field)
|
||||
case "Size":
|
||||
return ec.fieldContext_ManifestSummary_Size(ctx, field)
|
||||
case "IsSigned":
|
||||
return ec.fieldContext_ManifestSummary_IsSigned(ctx, field)
|
||||
case "Platform":
|
||||
return ec.fieldContext_ManifestSummary_Platform(ctx, field)
|
||||
case "DownloadCount":
|
||||
|
@ -4194,6 +4318,47 @@ func (ec *executionContext) fieldContext_ManifestSummary_Size(ctx context.Contex
|
|||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ManifestSummary_IsSigned(ctx context.Context, field graphql.CollectedField, obj *ManifestSummary) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ManifestSummary_IsSigned(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.IsSigned, nil
|
||||
})
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
return graphql.Null
|
||||
}
|
||||
if resTmp == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
res := resTmp.(*bool)
|
||||
fc.Result = res
|
||||
return ec.marshalOBoolean2ᚖbool(ctx, field.Selections, res)
|
||||
}
|
||||
|
||||
func (ec *executionContext) fieldContext_ManifestSummary_IsSigned(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 Boolean does not have child fields")
|
||||
},
|
||||
}
|
||||
return fc, nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) _ManifestSummary_Platform(ctx context.Context, field graphql.CollectedField, obj *ManifestSummary) (ret graphql.Marshaler) {
|
||||
fc, err := ec.fieldContext_ManifestSummary_Platform(ctx, field)
|
||||
if err != nil {
|
||||
|
@ -4779,6 +4944,10 @@ func (ec *executionContext) fieldContext_PaginatedImagesResult_Results(ctx conte
|
|||
return ec.fieldContext_ImageSummary_RepoName(ctx, field)
|
||||
case "Tag":
|
||||
return ec.fieldContext_ImageSummary_Tag(ctx, field)
|
||||
case "Digest":
|
||||
return ec.fieldContext_ImageSummary_Digest(ctx, field)
|
||||
case "MediaType":
|
||||
return ec.fieldContext_ImageSummary_MediaType(ctx, field)
|
||||
case "Manifests":
|
||||
return ec.fieldContext_ImageSummary_Manifests(ctx, field)
|
||||
case "Size":
|
||||
|
@ -5663,6 +5832,10 @@ func (ec *executionContext) fieldContext_Query_Image(ctx context.Context, field
|
|||
return ec.fieldContext_ImageSummary_RepoName(ctx, field)
|
||||
case "Tag":
|
||||
return ec.fieldContext_ImageSummary_Tag(ctx, field)
|
||||
case "Digest":
|
||||
return ec.fieldContext_ImageSummary_Digest(ctx, field)
|
||||
case "MediaType":
|
||||
return ec.fieldContext_ImageSummary_MediaType(ctx, field)
|
||||
case "Manifests":
|
||||
return ec.fieldContext_ImageSummary_Manifests(ctx, field)
|
||||
case "Size":
|
||||
|
@ -6160,6 +6333,10 @@ func (ec *executionContext) fieldContext_RepoInfo_Images(ctx context.Context, fi
|
|||
return ec.fieldContext_ImageSummary_RepoName(ctx, field)
|
||||
case "Tag":
|
||||
return ec.fieldContext_ImageSummary_Tag(ctx, field)
|
||||
case "Digest":
|
||||
return ec.fieldContext_ImageSummary_Digest(ctx, field)
|
||||
case "MediaType":
|
||||
return ec.fieldContext_ImageSummary_MediaType(ctx, field)
|
||||
case "Manifests":
|
||||
return ec.fieldContext_ImageSummary_Manifests(ctx, field)
|
||||
case "Size":
|
||||
|
@ -6556,6 +6733,10 @@ func (ec *executionContext) fieldContext_RepoSummary_NewestImage(ctx context.Con
|
|||
return ec.fieldContext_ImageSummary_RepoName(ctx, field)
|
||||
case "Tag":
|
||||
return ec.fieldContext_ImageSummary_Tag(ctx, field)
|
||||
case "Digest":
|
||||
return ec.fieldContext_ImageSummary_Digest(ctx, field)
|
||||
case "MediaType":
|
||||
return ec.fieldContext_ImageSummary_MediaType(ctx, field)
|
||||
case "Manifests":
|
||||
return ec.fieldContext_ImageSummary_Manifests(ctx, field)
|
||||
case "Size":
|
||||
|
@ -8827,6 +9008,14 @@ func (ec *executionContext) _ImageSummary(ctx context.Context, sel ast.Selection
|
|||
|
||||
out.Values[i] = ec._ImageSummary_Tag(ctx, field, obj)
|
||||
|
||||
case "Digest":
|
||||
|
||||
out.Values[i] = ec._ImageSummary_Digest(ctx, field, obj)
|
||||
|
||||
case "MediaType":
|
||||
|
||||
out.Values[i] = ec._ImageSummary_MediaType(ctx, field, obj)
|
||||
|
||||
case "Manifests":
|
||||
|
||||
out.Values[i] = ec._ImageSummary_Manifests(ctx, field, obj)
|
||||
|
@ -9019,6 +9208,10 @@ func (ec *executionContext) _ManifestSummary(ctx context.Context, sel ast.Select
|
|||
|
||||
out.Values[i] = ec._ManifestSummary_Size(ctx, field, obj)
|
||||
|
||||
case "IsSigned":
|
||||
|
||||
out.Values[i] = ec._ManifestSummary_IsSigned(ctx, field, obj)
|
||||
|
||||
case "Platform":
|
||||
|
||||
out.Values[i] = ec._ManifestSummary_Platform(ctx, field, obj)
|
||||
|
|
|
@ -91,6 +91,10 @@ type ImageSummary struct {
|
|||
RepoName *string `json:"RepoName"`
|
||||
// Tag identifying the image within the repository
|
||||
Tag *string `json:"Tag"`
|
||||
// The digest of the descriptor of this image
|
||||
Digest *string `json:"Digest"`
|
||||
// The media type of the descriptor of this image
|
||||
MediaType *string `json:"MediaType"`
|
||||
// List of manifests for all supported versions of the image for different operating systems and architectures
|
||||
Manifests []*ManifestSummary `json:"Manifests"`
|
||||
// Total size of the files associated with all images (manifest, config, layers)
|
||||
|
@ -162,6 +166,8 @@ type ManifestSummary struct {
|
|||
LastUpdated *time.Time `json:"LastUpdated"`
|
||||
// Total size of the files associated with this manifest (manifest, config, layers)
|
||||
Size *string `json:"Size"`
|
||||
// True if the manifest has a signature associated with it, false otherwise
|
||||
IsSigned *bool `json:"IsSigned"`
|
||||
// OS and architecture supported by this image
|
||||
Platform *Platform `json:"Platform"`
|
||||
// Total numer of image manifest downloads from this repository
|
||||
|
|
|
@ -124,6 +124,14 @@ type ImageSummary {
|
|||
"""
|
||||
Tag: String
|
||||
"""
|
||||
The digest of the descriptor of this image
|
||||
"""
|
||||
Digest: String
|
||||
"""
|
||||
The media type of the descriptor of this image
|
||||
"""
|
||||
MediaType: String
|
||||
"""
|
||||
List of manifests for all supported versions of the image for different operating systems and architectures
|
||||
"""
|
||||
Manifests: [ManifestSummary]
|
||||
|
@ -210,6 +218,10 @@ type ManifestSummary {
|
|||
"""
|
||||
Size: String
|
||||
"""
|
||||
True if the manifest has a signature associated with it, false otherwise
|
||||
"""
|
||||
IsSigned: Boolean
|
||||
"""
|
||||
OS and architecture supported by this image
|
||||
"""
|
||||
Platform: Platform
|
||||
|
|
Loading…
Add table
Reference in a new issue