feat(test): added image builder for use in tests (#1583)
Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
parent
4194489868
commit
abba6aa3cf
@ -2121,15 +2121,10 @@ func TestGroupsPermissionsForLDAP(t *testing.T) {
|
||||
cm.StartAndWait(port)
|
||||
defer cm.StopServer()
|
||||
|
||||
cfg, layers, manifest, err := test.GetImageComponents(10000)
|
||||
So(err, ShouldBeNil)
|
||||
img := test.CreateDefaultImage()
|
||||
|
||||
err = test.UploadImageWithBasicAuth(
|
||||
test.Image{
|
||||
Config: cfg,
|
||||
Layers: layers,
|
||||
Manifest: manifest,
|
||||
}, baseURL, repo,
|
||||
err = test.UploadImageWithBasicAuthRef(
|
||||
img, baseURL, repo, img.DigestStr(),
|
||||
username, passphrase)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -1503,13 +1503,13 @@ func runDisplayIndexTests(baseURL string) {
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE
|
||||
// repo multi-arch * 0f844b3e false 1.5kB
|
||||
// linux/amd64 2ab1a275 false 634B
|
||||
// windows/arm64/v6 55fdd23a false 444B
|
||||
// repo multi-arch * 28665f71 false 1.5kB
|
||||
// linux/amd64 02e0ac42 false 644B
|
||||
// windows/arm64/v6 5e09b7f9 false 444B
|
||||
So(actual, ShouldContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 0f844b3e false 1.5kB ")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 2ab1a275 false 634B ")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 55fdd23a false 501B")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 28665f71 false 1.5kB ")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 02e0ac42 false 644B ")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 5e09b7f9 false 506B")
|
||||
})
|
||||
|
||||
Convey("Test Image Index Verbose", func() {
|
||||
@ -1531,18 +1531,18 @@ func runDisplayIndexTests(baseURL string) {
|
||||
actual := strings.TrimSpace(str)
|
||||
// Actual cli output should be something similar to (order of images may differ):
|
||||
// REPOSITORY TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE
|
||||
// repo multi-arch * 0f844b3e false 1.5kB
|
||||
// linux/amd64 2ab1a275 58cc9abe false 634B
|
||||
// repo multi-arch * 28665f71 false 1.5kB
|
||||
// linux/amd64 02e0ac42 58cc9abe false 644B
|
||||
// cbb5b121 4B
|
||||
// a00291e8 4B
|
||||
// windows/arm64/v6 55fdd23a 5132a1cd false 501B
|
||||
// windows/arm64/v6 5e09b7f9 5132a1cd false 506B
|
||||
// 7d08ce29 4B
|
||||
So(actual, ShouldContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST CONFIG SIGNED LAYERS SIZE")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 0f844b3e false 1.5kB")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 2ab1a275 58cc9abe false 634B")
|
||||
So(actual, ShouldContainSubstring, "repo multi-arch * 28665f71 false 1.5kB")
|
||||
So(actual, ShouldContainSubstring, "linux/amd64 02e0ac42 58cc9abe false 644B")
|
||||
So(actual, ShouldContainSubstring, "cbb5b121 4B")
|
||||
So(actual, ShouldContainSubstring, "a00291e8 4B")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 55fdd23a 5132a1cd false 501B")
|
||||
So(actual, ShouldContainSubstring, "windows/arm64/v6 5e09b7f9 5132a1cd false 506B")
|
||||
So(actual, ShouldContainSubstring, "7d08ce29 4B")
|
||||
})
|
||||
}
|
||||
@ -1552,42 +1552,35 @@ func uploadTestMultiarch(baseURL string) {
|
||||
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{
|
||||
image1 := test.CreateImageWith().
|
||||
LayerBlobs([][]byte{
|
||||
layer11,
|
||||
layer12,
|
||||
},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
}).
|
||||
ImageConfig(
|
||||
ispec.Image{
|
||||
Platform: ispec.Platform{OS: "linux", Architecture: "amd64"},
|
||||
},
|
||||
).Build()
|
||||
|
||||
// ------ Define Image2
|
||||
layer21 := []byte{21, 22, 23, 24}
|
||||
|
||||
image2, err := test.GetImageWithComponents(
|
||||
ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
OS: "windows",
|
||||
Architecture: "arm64",
|
||||
Variant: "v6",
|
||||
},
|
||||
},
|
||||
[][]byte{
|
||||
image2 := test.CreateImageWith().
|
||||
LayerBlobs([][]byte{
|
||||
layer21,
|
||||
},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
}).
|
||||
ImageConfig(
|
||||
ispec.Image{
|
||||
Platform: ispec.Platform{OS: "windows", Architecture: "arm64", Variant: "v6"},
|
||||
},
|
||||
).Build()
|
||||
|
||||
// ------- Upload The multiarch image
|
||||
|
||||
multiarch := test.GetMultiarchImageForImages("multi-arch", []test.Image{image1, image2})
|
||||
multiarch := test.GetMultiarchImageForImages([]test.Image{image1, image2})
|
||||
|
||||
err = test.UploadMultiarchImage(multiarch, baseURL, "repo")
|
||||
err := test.UploadMultiarchImageWithRef(multiarch, baseURL, "repo", "multi-arch")
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
@ -205,36 +204,26 @@ func TestReferrerCLI(t *testing.T) {
|
||||
defer cm.StopServer()
|
||||
|
||||
repo := repoName
|
||||
image, err := test.GetRandomImage("tag")
|
||||
So(err, ShouldBeNil)
|
||||
imgDigest, err := image.Digest()
|
||||
image := test.CreateRandomImage()
|
||||
|
||||
err := test.UploadImageWithRef(image, baseURL, repo, "tag")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = test.UploadImage(image, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
ref1 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
RandomConfig().
|
||||
Subject(image.DescriptorRef()).Build()
|
||||
|
||||
// add referrers
|
||||
ref1, err := test.GetImageWithSubject(imgDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
ref1.Reference = ""
|
||||
ref2 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
ArtifactConfig(customArtTypeV1).
|
||||
Subject(image.DescriptorRef()).Build()
|
||||
|
||||
ref1Digest, err := ref1.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
ref2, err := test.GetImageWithSubject(imgDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
ref2.Reference = ""
|
||||
ref2.Manifest.Config.MediaType = customArtTypeV1
|
||||
ref2Digest, err := ref2.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
ref3, err := test.GetImageWithSubject(imgDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
ref3.Manifest.ArtifactType = customArtTypeV2
|
||||
ref3.Manifest.Config = ispec.DescriptorEmptyJSON
|
||||
ref3.Reference = ""
|
||||
ref3Digest, err := ref3.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
ref3 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
RandomConfig().
|
||||
ArtifactType(customArtTypeV2).
|
||||
Subject(image.DescriptorRef()).Build()
|
||||
|
||||
err = test.UploadImage(ref1, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
@ -245,7 +234,7 @@ func TestReferrerCLI(t *testing.T) {
|
||||
err = test.UploadImage(ref3, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
args := []string{"reftest", "--subject", repo + "@" + imgDigest.String()}
|
||||
args := []string{"reftest", "--subject", repo + "@" + image.DigestStr()}
|
||||
|
||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||
baseURL))
|
||||
@ -262,9 +251,9 @@ func TestReferrerCLI(t *testing.T) {
|
||||
space := regexp.MustCompile(`\s+`)
|
||||
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 557 B "+ref1Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/custom.art.type.v1 547 B "+ref2Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/custom.art.type.v2 610 B "+ref3Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
||||
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
||||
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
||||
|
||||
fmt.Println(buff.String())
|
||||
|
||||
@ -286,9 +275,9 @@ func TestReferrerCLI(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 557 B "+ref1Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/custom.art.type.v1 547 B "+ref2Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/custom.art.type.v2 610 B "+ref3Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
||||
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
||||
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
||||
|
||||
fmt.Println(buff.String())
|
||||
})
|
||||
@ -312,48 +301,38 @@ func TestReferrerCLI(t *testing.T) {
|
||||
defer cm.StopServer()
|
||||
|
||||
repo := repoName
|
||||
image, err := test.GetRandomImage("tag")
|
||||
So(err, ShouldBeNil)
|
||||
imgDigest, err := image.Digest()
|
||||
image := test.CreateRandomImage()
|
||||
|
||||
err := test.UploadImageWithRef(image, baseURL, repo, "tag")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = test.UploadImage(image, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
ref1 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
RandomConfig().
|
||||
Subject(image.DescriptorRef()).Build()
|
||||
|
||||
// add referrers
|
||||
ref1, err := test.GetImageWithSubject(imgDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
ref1Digest, err := ref1.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
ref2 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
ArtifactConfig(customArtTypeV1).
|
||||
Subject(image.DescriptorRef()).Build()
|
||||
|
||||
ref2, err := test.GetImageWithSubject(imgDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
ref2.Manifest.Config.MediaType = customArtTypeV1
|
||||
ref2Digest, err := ref2.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
ref3 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
RandomConfig().
|
||||
ArtifactType(customArtTypeV2).
|
||||
Subject(image.DescriptorRef()).Build()
|
||||
|
||||
ref3, err := test.GetImageWithSubject(imgDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
ref3.Manifest.ArtifactType = customArtTypeV2
|
||||
ref3.Manifest.Config = ispec.DescriptorEmptyJSON
|
||||
|
||||
ref3Digest, err := ref3.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
ref1.Reference = ""
|
||||
err = test.UploadImage(ref1, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
ref2.Reference = ""
|
||||
err = test.UploadImage(ref2, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
ref3.Reference = ""
|
||||
err = test.UploadImage(ref3, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// get referrers by digest
|
||||
args := []string{"reftest", "--subject", repo + "@" + imgDigest.String()}
|
||||
args := []string{"reftest", "--subject", repo + "@" + image.DigestStr()}
|
||||
|
||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||
baseURL))
|
||||
@ -369,9 +348,9 @@ func TestReferrerCLI(t *testing.T) {
|
||||
space := regexp.MustCompile(`\s+`)
|
||||
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 557 B "+ref1Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/custom.art.type.v1 547 B "+ref2Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/custom.art.type.v2 610 B "+ref3Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
||||
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
||||
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
||||
fmt.Println(buff.String())
|
||||
|
||||
os.Remove(configPath)
|
||||
@ -390,9 +369,9 @@ func TestReferrerCLI(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||
So(str, ShouldContainSubstring, "ARTIFACT TYPE SIZE DIGEST")
|
||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 557 B "+ref1Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/custom.art.type.v1 547 B "+ref2Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/custom.art.type.v2 610 B "+ref3Digest.String())
|
||||
So(str, ShouldContainSubstring, "application/vnd.oci.image.config.v1+json 563 B "+ref1.DigestStr())
|
||||
So(str, ShouldContainSubstring, "custom.art.type.v1 551 B "+ref2.DigestStr())
|
||||
So(str, ShouldContainSubstring, "custom.art.type.v2 611 B "+ref3.DigestStr())
|
||||
fmt.Println(buff.String())
|
||||
})
|
||||
}
|
||||
@ -417,41 +396,39 @@ func TestFormatsReferrersCLI(t *testing.T) {
|
||||
defer cm.StopServer()
|
||||
|
||||
repo := repoName
|
||||
image, err := test.GetRandomImage("tag")
|
||||
So(err, ShouldBeNil)
|
||||
imgDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
image := test.CreateRandomImage()
|
||||
|
||||
err = test.UploadImage(image, baseURL, repo)
|
||||
err := test.UploadImageWithRef(image, baseURL, repo, "tag")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// add referrers
|
||||
ref1, err := test.GetImageWithSubject(imgDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
ref1 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
RandomConfig().
|
||||
Subject(image.DescriptorRef()).Build()
|
||||
|
||||
ref2, err := test.GetImageWithSubject(imgDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
ref2.Manifest.Config.MediaType = customArtTypeV1
|
||||
ref2 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
ArtifactConfig(customArtTypeV1).
|
||||
Subject(image.DescriptorRef()).Build()
|
||||
|
||||
ref3, err := test.GetImageWithSubject(imgDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
ref3.Manifest.ArtifactType = customArtTypeV2
|
||||
ref3.Manifest.Config = ispec.DescriptorEmptyJSON
|
||||
ref3 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
RandomConfig().
|
||||
ArtifactType(customArtTypeV2).
|
||||
Subject(image.DescriptorRef()).Build()
|
||||
|
||||
ref1.Reference = ""
|
||||
err = test.UploadImage(ref1, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
ref2.Reference = ""
|
||||
err = test.UploadImage(ref2, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
ref3.Reference = ""
|
||||
err = test.UploadImage(ref3, baseURL, repo)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("JSON format", func() {
|
||||
args := []string{"reftest", "--output", "json", "--subject", repo + "@" + imgDigest.String()}
|
||||
args := []string{"reftest", "--output", "json", "--subject", repo + "@" + image.DigestStr()}
|
||||
|
||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||
baseURL))
|
||||
@ -469,7 +446,7 @@ func TestFormatsReferrersCLI(t *testing.T) {
|
||||
fmt.Println(buff.String())
|
||||
})
|
||||
Convey("YAML format", func() {
|
||||
args := []string{"reftest", "--output", "yaml", "--subject", repo + "@" + imgDigest.String()}
|
||||
args := []string{"reftest", "--output", "yaml", "--subject", repo + "@" + image.DigestStr()}
|
||||
|
||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||
baseURL))
|
||||
@ -487,7 +464,7 @@ func TestFormatsReferrersCLI(t *testing.T) {
|
||||
fmt.Println(buff.String())
|
||||
})
|
||||
Convey("Invalid format", func() {
|
||||
args := []string{"reftest", "--output", "invalid_format", "--subject", repo + "@" + imgDigest.String()}
|
||||
args := []string{"reftest", "--output", "invalid_format", "--subject", repo + "@" + image.DigestStr()}
|
||||
|
||||
configPath := makeConfigFile(fmt.Sprintf(`{"configs":[{"_name":"reftest","url":"%s","showspinner":false}]}`,
|
||||
baseURL))
|
||||
|
@ -105,26 +105,24 @@ func TestSearchCLI(t *testing.T) {
|
||||
r3tag2 = "repo3tag2"
|
||||
)
|
||||
|
||||
image1, err := test.GetImageWithConfig(ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
OS: "Os",
|
||||
Architecture: "Arch",
|
||||
},
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
img1Digest, err := image1.Digest()
|
||||
formatterDigest1 := img1Digest.Encoded()[:8]
|
||||
So(err, ShouldBeNil)
|
||||
image1 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
ImageConfig(ispec.Image{
|
||||
Created: test.DefaultTimeRef(),
|
||||
Platform: ispec.Platform{OS: "Os", Architecture: "Arch"},
|
||||
}).
|
||||
Build()
|
||||
formatterDigest1 := image1.Digest().Encoded()[:8]
|
||||
|
||||
image2, err := test.GetRandomImage("")
|
||||
So(err, ShouldBeNil)
|
||||
img2Digest, err := image2.Digest()
|
||||
formatterDigest2 := img2Digest.Encoded()[:8]
|
||||
So(err, ShouldBeNil)
|
||||
image2 := test.CreateImageWith().
|
||||
RandomLayers(1, 10).
|
||||
DefaultConfig().
|
||||
Build()
|
||||
formatterDigest2 := image2.Digest().Encoded()[:8]
|
||||
|
||||
// repo1
|
||||
image1.Reference = r1tag1
|
||||
err = test.UploadImage(image1, baseURL, repo1)
|
||||
err := test.UploadImage(image1, baseURL, repo1)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
image2.Reference = r1tag2
|
||||
@ -168,7 +166,7 @@ func TestSearchCLI(t *testing.T) {
|
||||
space := regexp.MustCompile(`\s+`)
|
||||
str := strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||
So(str, ShouldContainSubstring, "NAME SIZE LAST UPDATED DOWNLOADS STARS PLATFORMS")
|
||||
So(str, ShouldContainSubstring, "repo/test/alpine 1.1kB 0001-01-01 00:00:00 +0000 UTC 0 0")
|
||||
So(str, ShouldContainSubstring, "repo/test/alpine 1.1kB 2010-01-01 01:01:01 +0000 UTC 0 0")
|
||||
So(str, ShouldContainSubstring, "Os/Arch")
|
||||
So(str, ShouldContainSubstring, "linux/amd64")
|
||||
|
||||
@ -193,8 +191,8 @@ func TestSearchCLI(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
str = strings.TrimSpace(space.ReplaceAllString(buff.String(), " "))
|
||||
So(str, ShouldContainSubstring, "REPOSITORY TAG OS/ARCH DIGEST SIGNED SIZE")
|
||||
So(str, ShouldContainSubstring, "repo/alpine repo2tag1 Os/Arch "+formatterDigest1+" false 577B")
|
||||
So(str, ShouldContainSubstring, "repo/alpine repo2tag2 linux/amd64 "+formatterDigest2+" false 524B")
|
||||
So(str, ShouldContainSubstring, "repo/alpine repo2tag1 Os/Arch "+formatterDigest1+" false 525B")
|
||||
So(str, ShouldContainSubstring, "repo/alpine repo2tag2 linux/amd64 "+formatterDigest2+" false 552B")
|
||||
|
||||
fmt.Println("\n", buff.String())
|
||||
})
|
||||
@ -233,15 +231,13 @@ func TestFormatsSearchCLI(t *testing.T) {
|
||||
r3tag2 = "repo3tag2"
|
||||
)
|
||||
|
||||
image1, err := test.GetRandomImage("")
|
||||
So(err, ShouldBeNil)
|
||||
image1 := test.CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build()
|
||||
|
||||
image2, err := test.GetRandomImage("")
|
||||
So(err, ShouldBeNil)
|
||||
image2 := test.CreateImageWith().RandomLayers(1, 10).DefaultConfig().Build()
|
||||
|
||||
// repo1
|
||||
image1.Reference = r1tag1
|
||||
err = test.UploadImage(image1, baseURL, repo1)
|
||||
err := test.UploadImage(image1, baseURL, repo1)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
image2.Reference = r1tag2
|
||||
|
@ -1568,8 +1568,7 @@ func TestFixedTagsWithIndex(t *testing.T) {
|
||||
Platform: ispec.Platform{OS: "linux", Architecture: "amd64"},
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
vulnDigest, err := vulnManifest.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
vulnDigest := vulnManifest.Digest()
|
||||
|
||||
fixedManifestCreated := time.Date(2010, 1, 1, 1, 1, 1, 1, time.UTC)
|
||||
fixedManifest, err := GetImageWithConfig(ispec.Image{
|
||||
@ -1577,14 +1576,12 @@ func TestFixedTagsWithIndex(t *testing.T) {
|
||||
Platform: ispec.Platform{OS: "windows", Architecture: "amd64"},
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
fixedDigest, err := fixedManifest.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
fixedDigest := fixedManifest.Digest()
|
||||
|
||||
multiArch := GetMultiarchImageForImages("multi-arch-tag", []Image{fixedManifest, vulnManifest})
|
||||
multiArchDigest, err := multiArch.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
multiArch := GetMultiarchImageForImages([]Image{fixedManifest, vulnManifest})
|
||||
multiArchDigest := multiArch.Digest()
|
||||
|
||||
err = UploadMultiarchImage(multiArch, baseURL, "repo")
|
||||
err = UploadMultiarchImageWithRef(multiArch, baseURL, "repo", "multi-arch-tag")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// oldest vulnerability
|
||||
|
@ -46,21 +46,13 @@ func TestScanningByDigest(t *testing.T) {
|
||||
cm.StartAndWait(port)
|
||||
defer cm.StopServer()
|
||||
// push index with 2 manifests: one with vulns and one without
|
||||
vulnImage, err := test.GetVulnImage("")
|
||||
So(err, ShouldBeNil)
|
||||
vulnDigest, err := vulnImage.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
vulnImage := test.CreateVulnerableImage()
|
||||
|
||||
simpleImage, err := test.GetRandomImage("")
|
||||
So(err, ShouldBeNil)
|
||||
simpleDigest, err := simpleImage.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
simpleImage := test.CreateRandomImage()
|
||||
|
||||
multiArch := test.GetMultiarchImageForImages("multi-arch-tag", []test.Image{simpleImage, vulnImage})
|
||||
multiArchDigest, err := multiArch.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
multiArch := test.GetMultiarchImageForImages([]test.Image{simpleImage, vulnImage})
|
||||
|
||||
err = test.UploadMultiarchImage(multiArch, baseURL, "multi-arch")
|
||||
err := test.UploadMultiarchImageWithRef(multiArch, baseURL, "multi-arch", "multi-arch-tag")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// scan
|
||||
@ -69,17 +61,17 @@ func TestScanningByDigest(t *testing.T) {
|
||||
err = scanner.UpdateDB()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
cveMap, err := scanner.ScanImage("multi-arch@" + vulnDigest.String())
|
||||
cveMap, err := scanner.ScanImage("multi-arch@" + vulnImage.DigestStr())
|
||||
So(err, ShouldBeNil)
|
||||
So(cveMap, ShouldContainKey, test.Vulnerability1ID)
|
||||
So(cveMap, ShouldContainKey, test.Vulnerability2ID)
|
||||
So(cveMap, ShouldContainKey, test.Vulnerability3ID)
|
||||
|
||||
cveMap, err = scanner.ScanImage("multi-arch@" + simpleDigest.String())
|
||||
cveMap, err = scanner.ScanImage("multi-arch@" + simpleImage.DigestStr())
|
||||
So(err, ShouldBeNil)
|
||||
So(cveMap, ShouldBeEmpty)
|
||||
|
||||
cveMap, err = scanner.ScanImage("multi-arch@" + multiArchDigest.String())
|
||||
cveMap, err = scanner.ScanImage("multi-arch@" + multiArch.DigestStr())
|
||||
So(err, ShouldBeNil)
|
||||
So(cveMap, ShouldContainKey, test.Vulnerability1ID)
|
||||
So(cveMap, ShouldContainKey, test.Vulnerability2ID)
|
||||
@ -120,7 +112,7 @@ func TestScannerErrors(t *testing.T) {
|
||||
|
||||
func TestVulnerableLayer(t *testing.T) {
|
||||
Convey("Vulnerable layer", t, func() {
|
||||
vulnerableLayer, err := test.GetLayerWithVulnerability(1)
|
||||
vulnerableLayer, err := test.GetLayerWithVulnerability()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
created, err := time.Parse(time.RFC3339, "2023-03-29T18:19:24Z")
|
||||
@ -142,15 +134,10 @@ func TestVulnerableLayer(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
img, err := test.GetImageWithComponents(
|
||||
config,
|
||||
[][]byte{
|
||||
vulnerableLayer,
|
||||
},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
imgDigest, err := img.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
img := test.CreateImageWith().
|
||||
LayerBlobs([][]byte{vulnerableLayer}).
|
||||
ImageConfig(config).
|
||||
Build()
|
||||
|
||||
tempDir := t.TempDir()
|
||||
|
||||
@ -182,7 +169,7 @@ func TestVulnerableLayer(t *testing.T) {
|
||||
err = scanner.UpdateDB()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
cveMap, err := scanner.ScanImage("repo@" + imgDigest.String())
|
||||
cveMap, err := scanner.ScanImage("repo@" + img.DigestStr())
|
||||
So(err, ShouldBeNil)
|
||||
t.Logf("cveMap: %v", cveMap)
|
||||
// As of July 15 2023 there are 3 CVEs: CVE-2023-1255, CVE-2023-2650, CVE-2023-2975
|
||||
|
@ -111,8 +111,7 @@ func TestDigestSearchHTTP(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
image2.Reference = ver001
|
||||
manifestDigest, err := image2.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := image2.Digest()
|
||||
|
||||
err = UploadImage(image2, baseURL, "zot-test")
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -1112,8 +1112,7 @@ func TestGetReferrersGQL(t *testing.T) {
|
||||
|
||||
targetImg, err := GetRandomImage("")
|
||||
So(err, ShouldBeNil)
|
||||
targetDigest, err := targetImg.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
targetDigest := targetImg.Digest()
|
||||
|
||||
err = UploadImage(targetImg, baseURL, "repo")
|
||||
So(err, ShouldBeNil)
|
||||
@ -1128,8 +1127,7 @@ func TestGetReferrersGQL(t *testing.T) {
|
||||
Digest: targetDigest,
|
||||
}
|
||||
|
||||
indexReferrerDigest, err := indexReferrer.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
indexReferrerDigest := indexReferrer.Digest()
|
||||
|
||||
err = UploadMultiarchImage(indexReferrer, baseURL, "repo")
|
||||
So(err, ShouldBeNil)
|
||||
@ -1545,8 +1543,7 @@ func TestExpandedRepoInfo(t *testing.T) {
|
||||
|
||||
image, err := GetRandomImage(test)
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := image.Digest()
|
||||
|
||||
err = UploadImage(image, baseURL, "repo")
|
||||
So(err, ShouldBeNil)
|
||||
@ -1713,7 +1710,7 @@ func TestExpandedRepoInfo(t *testing.T) {
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
multiImage1 := GetMultiarchImageForImages("1.0.0", []Image{indexSubImage11, indexSubImage12})
|
||||
multiImage1 := GetMultiarchImageForImages([]Image{indexSubImage11, indexSubImage12})
|
||||
|
||||
indexSubImage21, err := GetImageWithConfig(ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
@ -1739,15 +1736,13 @@ func TestExpandedRepoInfo(t *testing.T) {
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
multiImage2 := GetMultiarchImageForImages("2.0.0",
|
||||
[]Image{indexSubImage21, indexSubImage22, indexSubImage23},
|
||||
)
|
||||
multiImage2 := GetMultiarchImageForImages([]Image{indexSubImage21, indexSubImage22, indexSubImage23})
|
||||
|
||||
// ------- Write test Images
|
||||
err = WriteMultiArchImageToFileSystem(multiImage1, "repo", storeController)
|
||||
err = WriteMultiArchImageToFileSystem(multiImage1, "repo", "1.0.0", storeController)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = WriteMultiArchImageToFileSystem(multiImage2, "repo", storeController)
|
||||
err = WriteMultiArchImageToFileSystem(multiImage2, "repo", "2.0.0", storeController)
|
||||
So(err, ShouldBeNil)
|
||||
// ------- Start Server /tmp/TestExpandedRepoInfo4021254039/005
|
||||
|
||||
@ -4845,11 +4840,11 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
multiImage := GetMultiarchImageForImages("latest", []Image{
|
||||
multiImage := GetMultiarchImageForImages([]Image{
|
||||
imageAMD64,
|
||||
imageSomeArch,
|
||||
})
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "test-repo")
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "test-repo", "latest")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- BASE IMAGE -------------------
|
||||
|
||||
@ -4868,11 +4863,9 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
multiImage = GetMultiarchImageForImages("index-one-arch-same-layers", []Image{
|
||||
image1, image2,
|
||||
})
|
||||
multiImage = GetMultiarchImageForImages([]Image{image1, image2})
|
||||
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "index-one-arch-same-layers")
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "index-one-arch-same-layers", "index-one-arch-same-layers")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- SAME LAYERS -------------------
|
||||
|
||||
@ -4891,10 +4884,9 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
[][]byte{imageAMD64.Layers[0]},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
multiImage = GetMultiarchImageForImages("index-one-arch-less-layers", []Image{
|
||||
image1, image2,
|
||||
})
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "index-one-arch-less-layers")
|
||||
multiImage = GetMultiarchImageForImages([]Image{image1, image2})
|
||||
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "index-one-arch-less-layers", "index-one-arch-less-layers")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- LESS LAYERS -------------------
|
||||
|
||||
@ -4915,10 +4907,9 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
[][]byte{auxLayer},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
multiImage = GetMultiarchImageForImages("index-one-arch-less-layers-false", []Image{
|
||||
image1, image2,
|
||||
})
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "index-one-arch-less-layers-false")
|
||||
multiImage = GetMultiarchImageForImages([]Image{image1, image2})
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "index-one-arch-less-layers-false",
|
||||
"index-one-arch-less-layers-false")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- LESS LAYERS FALSE -------------------
|
||||
|
||||
@ -4937,11 +4928,9 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
append(imageAMD64.Layers, []byte{1, 3, 55}),
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
multiImage = GetMultiarchImageForImages("index-one-arch-more-layers", []Image{
|
||||
image1, image2,
|
||||
})
|
||||
multiImage = GetMultiarchImageForImages([]Image{image1, image2})
|
||||
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "index-one-arch-more-layers")
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "index-one-arch-more-layers", "index-one-arch-more-layers")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- MORE LAYERS -------------------
|
||||
|
||||
@ -4988,8 +4977,7 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
baseLinuxAMD64Digest, err := imageAMD64.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
baseLinuxAMD64Digest := imageAMD64.Digest()
|
||||
|
||||
imageSomeArch, err := GetImageWithComponents(
|
||||
ispec.Image{
|
||||
@ -5003,14 +4991,10 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
baseLinuxSomeArchDigest, err := imageSomeArch.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
baseLinuxSomeArchDigest := imageSomeArch.Digest()
|
||||
|
||||
multiImage := GetMultiarchImageForImages("index", []Image{
|
||||
imageAMD64,
|
||||
imageSomeArch,
|
||||
})
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "test-repo")
|
||||
multiImage := GetMultiarchImageForImages([]Image{imageAMD64, imageSomeArch})
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "test-repo", "index")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- BASE IMAGE FOR LINUX AMD64 -------------------
|
||||
|
||||
@ -5105,11 +5089,10 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
multiImage := GetMultiarchImageForImages("latest", []Image{
|
||||
imageAMD64,
|
||||
imageSomeArch,
|
||||
multiImage := GetMultiarchImageForImages([]Image{
|
||||
imageAMD64, imageSomeArch,
|
||||
})
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "test-repo")
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "test-repo", "latest")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- BASE IMAGE -------------------
|
||||
|
||||
@ -5127,11 +5110,11 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
imageAMD64.Layers,
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
multiImage = GetMultiarchImageForImages("index-one-arch-same-layers", []Image{
|
||||
|
||||
multiImage = GetMultiarchImageForImages([]Image{
|
||||
image1, image2,
|
||||
})
|
||||
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "index-one-arch-same-layers")
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "index-one-arch-same-layers", "index-one-arch-same-layers")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- SAME LAYERS -------------------
|
||||
|
||||
@ -5150,10 +5133,10 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
[][]byte{imageAMD64.Layers[0]},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
multiImage = GetMultiarchImageForImages("index-one-arch-less-layers", []Image{
|
||||
multiImage = GetMultiarchImageForImages([]Image{
|
||||
image1, image2,
|
||||
})
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "index-one-arch-less-layers")
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "index-one-arch-less-layers", "index-one-arch-less-layers")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- LESS LAYERS -------------------
|
||||
|
||||
@ -5172,10 +5155,11 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
[][]byte{{99, 100, 102}},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
multiImage = GetMultiarchImageForImages("index-one-arch-less-layers-false", []Image{
|
||||
multiImage = GetMultiarchImageForImages([]Image{
|
||||
image1, image2,
|
||||
})
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "index-one-arch-less-layers-false")
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "index-one-arch-less-layers-false",
|
||||
"index-one-arch-less-layers-false")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- LESS LAYERS FALSE -------------------
|
||||
|
||||
@ -5198,12 +5182,11 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
},
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
multiImage = GetMultiarchImageForImages("index-one-arch-more-layers", []Image{
|
||||
image1,
|
||||
image2,
|
||||
})
|
||||
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "index-one-arch-more-layers")
|
||||
multiImage = GetMultiarchImageForImages([]Image{
|
||||
image1, image2,
|
||||
})
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "index-one-arch-more-layers", "index-one-arch-more-layers")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- MORE LAYERS -------------------
|
||||
|
||||
@ -5250,8 +5233,7 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
baseLinuxAMD64Digest, err := imageAMD64.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
baseLinuxAMD64Digest := imageAMD64.Digest()
|
||||
|
||||
imageSomeArch, err := GetImageWithComponents(
|
||||
ispec.Image{
|
||||
@ -5265,14 +5247,12 @@ func RunMetaDBIndexTests(baseURL, port string) {
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
baseLinuxSomeArchDigest, err := imageSomeArch.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
baseLinuxSomeArchDigest := imageSomeArch.Digest()
|
||||
|
||||
multiImage := GetMultiarchImageForImages("index", []Image{
|
||||
imageAMD64,
|
||||
imageSomeArch,
|
||||
multiImage := GetMultiarchImageForImages([]Image{
|
||||
imageAMD64, imageSomeArch,
|
||||
})
|
||||
err = UploadMultiarchImage(multiImage, baseURL, "test-repo")
|
||||
err = UploadMultiarchImageWithRef(multiImage, baseURL, "test-repo", "index")
|
||||
So(err, ShouldBeNil)
|
||||
// ---------------- BASE IMAGE FOR LINUX AMD64 -------------------
|
||||
|
||||
@ -5707,8 +5687,7 @@ func TestMetaDBWhenDeletingImages(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Delete a referrer", func() {
|
||||
referredImageDigest, err := image1.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
referredImageDigest := image1.Digest()
|
||||
|
||||
referrerImage, err := GetImageWithSubject(referredImageDigest, ispec.MediaTypeImageManifest)
|
||||
So(err, ShouldBeNil)
|
||||
@ -6192,8 +6171,7 @@ func TestImageSummary(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
image.Reference = tagTarget
|
||||
|
||||
manifestDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := image.Digest()
|
||||
|
||||
err = UploadImage(image, baseURL, repoName)
|
||||
So(err, ShouldBeNil)
|
||||
@ -6208,8 +6186,7 @@ func TestImageSummary(t *testing.T) {
|
||||
}
|
||||
referrerImage.Manifest.Config.MediaType = "application/test.artifact.type"
|
||||
referrerImage.Manifest.Annotations = map[string]string{"testAnnotationKey": "testAnnotationValue"}
|
||||
referrerManifestDigest, err := referrerImage.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
referrerManifestDigest := referrerImage.Digest()
|
||||
referrerImage.Reference = referrerManifestDigest.String()
|
||||
|
||||
err = UploadImage(referrerImage, baseURL, repoName)
|
||||
@ -6515,8 +6492,7 @@ func TestImageSummary(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
img1.Manifest.Config = ispec.DescriptorEmptyJSON
|
||||
img1.Manifest.ArtifactType = artType1
|
||||
digest1, err := img1.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
digest1 := img1.Digest()
|
||||
|
||||
err = UploadImage(img1, baseURL, "repo")
|
||||
So(err, ShouldBeNil)
|
||||
@ -6524,8 +6500,7 @@ func TestImageSummary(t *testing.T) {
|
||||
img2, err := GetRandomImage("art2")
|
||||
So(err, ShouldBeNil)
|
||||
img2.Manifest.Config.MediaType = artType2
|
||||
digest2, err := img2.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
digest2 := img2.Digest()
|
||||
|
||||
err = UploadImage(img2, baseURL, "repo")
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -4439,13 +4439,10 @@ func TestSyncedSignaturesMetaDB(t *testing.T) {
|
||||
defer scm.StopServer()
|
||||
|
||||
// Push an image
|
||||
destImage, err := test.GetRandomImage(tag)
|
||||
signedImage, err := test.GetRandomImage(tag)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
signedImageDigest, err := destImage.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = test.UploadImage(destImage, srcBaseURL, repoName)
|
||||
err = test.UploadImage(signedImage, srcBaseURL, repoName)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = test.SignImageUsingNotary(repoName+":"+tag, srcPort)
|
||||
@ -4497,9 +4494,9 @@ func TestSyncedSignaturesMetaDB(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(repoMeta.Tags, ShouldContainKey, tag)
|
||||
So(len(repoMeta.Tags), ShouldEqual, 1)
|
||||
So(repoMeta.Signatures, ShouldContainKey, signedImageDigest.String())
|
||||
So(repoMeta.Signatures, ShouldContainKey, signedImage.DigestStr())
|
||||
|
||||
imageSignatures := repoMeta.Signatures[signedImageDigest.String()]
|
||||
imageSignatures := repoMeta.Signatures[signedImage.DigestStr()]
|
||||
So(imageSignatures, ShouldContainKey, signatures.CosignSignature)
|
||||
So(len(imageSignatures[signatures.CosignSignature]), ShouldEqual, 1)
|
||||
So(imageSignatures, ShouldContainKey, signatures.NotationSignature)
|
||||
|
@ -2688,11 +2688,9 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
|
||||
multiArch, err := test.GetRandomMultiarchImage("tag1")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
indexDigest, err := multiArch.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
indexDigest := multiArch.Digest()
|
||||
|
||||
indexData, err := multiArch.IndexData()
|
||||
So(err, ShouldBeNil)
|
||||
indexData := multiArch.IndexData()
|
||||
|
||||
err = metaDB.SetIndexData(indexDigest, indexData)
|
||||
So(err, ShouldBeNil)
|
||||
@ -2709,8 +2707,7 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
|
||||
image, err := test.GetRandomImage("tag")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
referredDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
referredDigest := image.Digest()
|
||||
|
||||
manifestBlob, err := json.Marshal(image.Manifest)
|
||||
So(err, ShouldBeNil)
|
||||
@ -2737,8 +2734,7 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
artifactDigest1, err := artifact1.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
artifactDigest1 := artifact1.Digest()
|
||||
|
||||
err = metaDB.SetReferrer("repo", referredDigest, mTypes.ReferrerInfo{
|
||||
Digest: artifactDigest1.String(),
|
||||
@ -2754,8 +2750,7 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
artifactDigest2, err := artifact2.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
artifactDigest2 := artifact2.Digest()
|
||||
|
||||
err = metaDB.SetReferrer("repo", referredDigest, mTypes.ReferrerInfo{
|
||||
Digest: artifactDigest2.String(),
|
||||
@ -2874,8 +2869,7 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
|
||||
Convey("FilterRepos", func() {
|
||||
img, err := test.GetRandomImage("img1")
|
||||
So(err, ShouldBeNil)
|
||||
imgDigest, err := img.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
imgDigest := img.Digest()
|
||||
|
||||
manifestData, err := NewManifestData(img.Manifest, img.Config)
|
||||
So(err, ShouldBeNil)
|
||||
@ -2885,8 +2879,7 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
|
||||
|
||||
multiarch, err := test.GetRandomMultiarchImage("multi")
|
||||
So(err, ShouldBeNil)
|
||||
multiarchDigest, err := multiarch.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
multiarchDigest := multiarch.Digest()
|
||||
|
||||
indexData, err := NewIndexData(multiarch.Index)
|
||||
So(err, ShouldBeNil)
|
||||
@ -2895,8 +2888,7 @@ func RunMetaDBTests(t *testing.T, metaDB mTypes.MetaDB, preparationFuncs ...func
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
for _, img := range multiarch.Images {
|
||||
digest, err := img.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
digest := img.Digest()
|
||||
|
||||
indManData1, err := NewManifestData(multiarch.Images[0].Manifest, multiarch.Images[0].Config)
|
||||
So(err, ShouldBeNil)
|
||||
|
@ -147,8 +147,7 @@ func TestVerifySignatures(t *testing.T) {
|
||||
manifestContent, err := json.Marshal(image.Manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := image.Digest()
|
||||
|
||||
_, _, _, err = signatures.VerifySignature("wrongType", []byte(""), "", manifestDigest, manifestContent, "repo")
|
||||
So(err, ShouldNotBeNil)
|
||||
@ -164,8 +163,7 @@ func TestVerifySignatures(t *testing.T) {
|
||||
manifestContent, err := json.Marshal(image.Manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := image.Digest()
|
||||
|
||||
Convey("cosignDir is not set", func() {
|
||||
_, _, _, err = signatures.VerifySignature("cosign", []byte(""), "", manifestDigest, manifestContent, repo)
|
||||
@ -300,8 +298,7 @@ func TestVerifySignatures(t *testing.T) {
|
||||
manifestContent, err := json.Marshal(image.Manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := image.Digest()
|
||||
|
||||
Convey("notationDir is not set", func() {
|
||||
_, _, _, err = signatures.VerifySignature("notation", []byte("signature"), "", manifestDigest, manifestContent, repo)
|
||||
|
@ -529,8 +529,7 @@ func RunParseStorageTests(rootDir string, metaDB mTypes.MetaDB) {
|
||||
signatureTag, err := test.GetCosignSignatureTagForManifest(image.Manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
missingImageDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
missingImageDigest := image.Digest()
|
||||
|
||||
// get the body of the signature
|
||||
config, layers, manifest, err = test.GetRandomImageComponents(100)
|
||||
@ -576,8 +575,7 @@ func RunParseStorageTests(rootDir string, metaDB mTypes.MetaDB) {
|
||||
image, err := test.GetRandomImage("tag")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest, err := image.Digest()
|
||||
So(err, ShouldBeNil)
|
||||
manifestDigest := image.Digest()
|
||||
|
||||
err = test.WriteImageToFileSystem(
|
||||
image,
|
||||
|
@ -15,13 +15,13 @@ import (
|
||||
"log"
|
||||
"math"
|
||||
"math/big"
|
||||
mathRand "math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -48,8 +48,6 @@ import (
|
||||
"oras.land/oras-go/v2/registry/remote"
|
||||
"oras.land/oras-go/v2/registry/remote/auth"
|
||||
|
||||
zerr "zotregistry.io/zot/errors"
|
||||
mTypes "zotregistry.io/zot/pkg/meta/types"
|
||||
"zotregistry.io/zot/pkg/storage"
|
||||
storageCommon "zotregistry.io/zot/pkg/storage/common"
|
||||
"zotregistry.io/zot/pkg/test/inject"
|
||||
@ -61,6 +59,8 @@ const (
|
||||
SleepTime = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
var ErrNoGoModFileFound = errors.New("test: no go.mod file found in parent directories")
|
||||
|
||||
var vulnerableLayer []byte //nolint: gochecknoglobals
|
||||
|
||||
var NotationPathLock = new(sync.Mutex) //nolint: gochecknoglobals
|
||||
@ -97,51 +97,11 @@ var (
|
||||
ErrPutIndex = errors.New("can't put index")
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
Manifest ispec.Manifest
|
||||
Config ispec.Image
|
||||
Layers [][]byte
|
||||
Reference string
|
||||
}
|
||||
|
||||
func (img Image) Digest() (godigest.Digest, error) {
|
||||
blob, err := json.Marshal(img.Manifest)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return godigest.FromBytes(blob), nil
|
||||
}
|
||||
|
||||
type ArtifactBlobs struct {
|
||||
Blob []byte
|
||||
MediaType string
|
||||
}
|
||||
|
||||
type MultiarchImage struct {
|
||||
Index ispec.Index
|
||||
Images []Image
|
||||
Reference string
|
||||
}
|
||||
|
||||
func (mi *MultiarchImage) Digest() (godigest.Digest, error) {
|
||||
indexBlob, err := json.Marshal(mi.Index)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return godigest.FromBytes(indexBlob), nil
|
||||
}
|
||||
|
||||
func (mi *MultiarchImage) IndexData() (mTypes.IndexData, error) {
|
||||
indexBlob, err := json.Marshal(mi.Index)
|
||||
if err != nil {
|
||||
return mTypes.IndexData{}, err
|
||||
}
|
||||
|
||||
return mTypes.IndexData{IndexBlob: indexBlob}, nil
|
||||
}
|
||||
|
||||
func GetFreePort() string {
|
||||
port, err := freeport.GetFreePort()
|
||||
if err != nil {
|
||||
@ -362,7 +322,7 @@ func WriteImageToFileSystem(image Image, repoName string, storeController storag
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteMultiArchImageToFileSystem(multiarchImage MultiarchImage, repoName string,
|
||||
func WriteMultiArchImageToFileSystem(multiarchImage MultiarchImage, repoName, ref string,
|
||||
storeController storage.StoreController,
|
||||
) error {
|
||||
store := storeController.GetImageStore(repoName)
|
||||
@ -384,7 +344,7 @@ func WriteMultiArchImageToFileSystem(multiarchImage MultiarchImage, repoName str
|
||||
return err
|
||||
}
|
||||
|
||||
_, _, err = store.PutImageManifest(repoName, multiarchImage.Reference, ispec.MediaTypeImageIndex,
|
||||
_, _, err = store.PutImageManifest(repoName, ref, ispec.MediaTypeImageIndex,
|
||||
indexBlob)
|
||||
|
||||
return err
|
||||
@ -646,47 +606,8 @@ const (
|
||||
Vulnerability3ID = "CVE-2023-2975"
|
||||
)
|
||||
|
||||
func GetVulnImage(ref string) (Image, error) {
|
||||
const skipStackFrame = 2
|
||||
|
||||
vulnerableLayer, err := GetLayerWithVulnerability(skipStackFrame)
|
||||
if err != nil {
|
||||
return Image{}, err
|
||||
}
|
||||
|
||||
vulnerableConfig := ispec.Image{
|
||||
Platform: ispec.Platform{
|
||||
Architecture: "amd64",
|
||||
OS: "linux",
|
||||
},
|
||||
Config: ispec.ImageConfig{
|
||||
Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
|
||||
Cmd: []string{"/bin/sh"},
|
||||
},
|
||||
RootFS: ispec.RootFS{
|
||||
Type: "layers",
|
||||
DiffIDs: []godigest.Digest{"sha256:f1417ff83b319fbdae6dd9cd6d8c9c88002dcd75ecf6ec201c8c6894681cf2b5"},
|
||||
},
|
||||
}
|
||||
|
||||
img, err := GetImageWithComponents(
|
||||
vulnerableConfig,
|
||||
[][]byte{
|
||||
vulnerableLayer,
|
||||
})
|
||||
if err != nil {
|
||||
return Image{}, err
|
||||
}
|
||||
|
||||
img.Reference = ref
|
||||
|
||||
return img, err
|
||||
}
|
||||
|
||||
func GetVulnImageWithConfig(ref string, config ispec.Image) (Image, error) {
|
||||
const skipStackFrame = 2
|
||||
|
||||
vulnerableLayer, err := GetLayerWithVulnerability(skipStackFrame)
|
||||
vulnerableLayer, err := GetLayerWithVulnerability()
|
||||
if err != nil {
|
||||
return Image{}, err
|
||||
}
|
||||
@ -716,44 +637,22 @@ func GetVulnImageWithConfig(ref string, config ispec.Image) (Image, error) {
|
||||
return img, err
|
||||
}
|
||||
|
||||
func GetLayerWithVulnerability(skip int) ([]byte, error) {
|
||||
func GetLayerWithVulnerability() ([]byte, error) {
|
||||
if vulnerableLayer != nil {
|
||||
return vulnerableLayer, nil
|
||||
}
|
||||
|
||||
_, b, _, ok := runtime.Caller(skip)
|
||||
if !ok {
|
||||
return []byte{}, zerr.ErrCallerInfo
|
||||
projectRootDir, err := GetProjectRootDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
absoluteCallerpath := filepath.Dir(b)
|
||||
fmt.Println(absoluteCallerpath)
|
||||
|
||||
// we know pkg folder inside zot must exist, and since all tests are called from within pkg we'll use it as reference
|
||||
relCallerPath := absoluteCallerpath[strings.LastIndex(absoluteCallerpath, "pkg"):]
|
||||
|
||||
relCallerSlice := strings.Split(relCallerPath, string(os.PathSeparator))
|
||||
fmt.Println(relCallerPath, relCallerSlice)
|
||||
|
||||
// we'll calculate how many folder we should go back to reach the root of the zot folder relative
|
||||
// to the callers position
|
||||
backPathSlice := make([]string, len(relCallerSlice))
|
||||
|
||||
for i := 0; i < len(backPathSlice); i++ {
|
||||
backPathSlice[i] = ".."
|
||||
}
|
||||
|
||||
backPath := filepath.Join(backPathSlice...)
|
||||
|
||||
// this is the path of the blob relative to the root of the zot folder
|
||||
vulnBlobPath := "test/data/alpine/blobs/sha256/f56be85fc22e46face30e2c3de3f7fe7c15f8fd7c4e5add29d7f64b87abdaa09"
|
||||
|
||||
var err error
|
||||
absoluteVulnBlobPath, _ := filepath.Abs(filepath.Join(projectRootDir, vulnBlobPath))
|
||||
|
||||
x, _ := filepath.Abs(filepath.Join(backPath, vulnBlobPath))
|
||||
_ = x
|
||||
|
||||
vulnerableLayer, err = os.ReadFile(filepath.Join(backPath, vulnBlobPath)) //nolint: lll
|
||||
vulnerableLayer, err := os.ReadFile(absoluteVulnBlobPath) //nolint: lll
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -761,6 +660,28 @@ func GetLayerWithVulnerability(skip int) ([]byte, error) {
|
||||
return vulnerableLayer, nil
|
||||
}
|
||||
|
||||
func GetProjectRootDir() (string, error) {
|
||||
workDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for {
|
||||
goModPath := filepath.Join(workDir, "go.mod")
|
||||
|
||||
_, err := os.Stat(goModPath)
|
||||
if err == nil {
|
||||
return workDir, nil
|
||||
}
|
||||
|
||||
if workDir == filepath.Dir(workDir) {
|
||||
return "", ErrNoGoModFileFound
|
||||
}
|
||||
|
||||
workDir = filepath.Dir(workDir)
|
||||
}
|
||||
}
|
||||
|
||||
func GetRandomLayer(size int) []byte {
|
||||
layer := make([]byte, size)
|
||||
|
||||
@ -975,10 +896,17 @@ func UploadImage(img Image, baseURL, repo string) error {
|
||||
return ErrPutBlob
|
||||
}
|
||||
}
|
||||
// upload config
|
||||
cblob, err := json.Marshal(img.Config)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
|
||||
var err error
|
||||
|
||||
cblob := img.ConfigDescriptor.Data
|
||||
|
||||
// we'll remove this check once we make the full transition to the new way of generating test images
|
||||
if len(cblob) == 0 {
|
||||
cblob, err = json.Marshal(img.Config)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cdigest := godigest.FromBytes(cblob)
|
||||
@ -1016,10 +944,14 @@ func UploadImage(img Image, baseURL, repo string) error {
|
||||
return ErrPostBlob
|
||||
}
|
||||
|
||||
// put manifest
|
||||
manifestBlob, err := json.Marshal(img.Manifest)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
manifestBlob := img.ManifestDescriptor.Data
|
||||
|
||||
// we'll remove this check once we make the full transition to the new way of generating test images
|
||||
if len(manifestBlob) == 0 {
|
||||
manifestBlob, err = json.Marshal(img.Manifest)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// validate manifest
|
||||
@ -1047,6 +979,115 @@ func UploadImage(img Image, baseURL, repo string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func UploadImageWithRef(img Image, baseURL, repo, ref string) error {
|
||||
for _, blob := range img.Layers {
|
||||
resp, err := resty.R().Post(baseURL + "/v2/" + repo + "/blobs/uploads/")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode() != http.StatusAccepted {
|
||||
return ErrPostBlob
|
||||
}
|
||||
|
||||
loc := resp.Header().Get("Location")
|
||||
|
||||
digest := godigest.FromBytes(blob).String()
|
||||
|
||||
resp, err = resty.R().
|
||||
SetHeader("Content-Length", fmt.Sprintf("%d", len(blob))).
|
||||
SetHeader("Content-Type", "application/octet-stream").
|
||||
SetQueryParam("digest", digest).
|
||||
SetBody(blob).
|
||||
Put(baseURL + loc)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode() != http.StatusCreated {
|
||||
return ErrPutBlob
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
cblob := img.ConfigDescriptor.Data
|
||||
|
||||
// we'll remove this check once we make the full transition to the new way of generating test images
|
||||
if len(cblob) == 0 {
|
||||
cblob, err = json.Marshal(img.Config)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cdigest := godigest.FromBytes(cblob)
|
||||
|
||||
if img.Manifest.Config.MediaType == ispec.MediaTypeEmptyJSON ||
|
||||
img.Manifest.Config.Digest == ispec.DescriptorEmptyJSON.Digest {
|
||||
cblob = ispec.DescriptorEmptyJSON.Data
|
||||
cdigest = ispec.DescriptorEmptyJSON.Digest
|
||||
}
|
||||
|
||||
resp, err := resty.R().
|
||||
Post(baseURL + "/v2/" + repo + "/blobs/uploads/")
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if inject.ErrStatusCode(resp.StatusCode()) != http.StatusAccepted || inject.ErrStatusCode(resp.StatusCode()) == -1 {
|
||||
return ErrPostBlob
|
||||
}
|
||||
|
||||
loc := Location(baseURL, resp)
|
||||
|
||||
// uploading blob should get 201
|
||||
resp, err = resty.R().
|
||||
SetHeader("Content-Length", fmt.Sprintf("%d", len(cblob))).
|
||||
SetHeader("Content-Type", "application/octet-stream").
|
||||
SetQueryParam("digest", cdigest.String()).
|
||||
SetBody(cblob).
|
||||
Put(loc)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if inject.ErrStatusCode(resp.StatusCode()) != http.StatusCreated || inject.ErrStatusCode(resp.StatusCode()) == -1 {
|
||||
return ErrPostBlob
|
||||
}
|
||||
|
||||
manifestBlob := img.ManifestDescriptor.Data
|
||||
|
||||
// we'll remove this check once we make the full transition to the new way of generating test images
|
||||
if len(manifestBlob) == 0 {
|
||||
manifestBlob, err = json.Marshal(img.Manifest)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// validate manifest
|
||||
if err := storageCommon.ValidateManifestSchema(manifestBlob); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err = resty.R().
|
||||
SetHeader("Content-type", ispec.MediaTypeImageManifest).
|
||||
SetBody(manifestBlob).
|
||||
Put(baseURL + "/v2/" + repo + "/manifests/" + ref)
|
||||
|
||||
if inject.ErrStatusCode(resp.StatusCode()) != http.StatusCreated {
|
||||
return ErrPutBlob
|
||||
}
|
||||
|
||||
if inject.ErrStatusCode(resp.StatusCode()) != http.StatusCreated {
|
||||
return ErrPutBlob
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteImage(repo, reference, baseURL string) (int, error) {
|
||||
resp, err := resty.R().Delete(
|
||||
fmt.Sprintf(baseURL+"/v2/%s/manifests/%s", repo, reference),
|
||||
@ -1715,6 +1756,96 @@ func UploadImageWithBasicAuth(img Image, baseURL, repo, user, password string) e
|
||||
return err
|
||||
}
|
||||
|
||||
func UploadImageWithBasicAuthRef(img Image, baseURL, repo, ref, user, password string) error {
|
||||
for _, blob := range img.Layers {
|
||||
resp, err := resty.R().
|
||||
SetBasicAuth(user, password).
|
||||
Post(baseURL + "/v2/" + repo + "/blobs/uploads/")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode() != http.StatusAccepted {
|
||||
return ErrPostBlob
|
||||
}
|
||||
|
||||
loc := resp.Header().Get("Location")
|
||||
|
||||
digest := godigest.FromBytes(blob).String()
|
||||
|
||||
resp, err = resty.R().
|
||||
SetBasicAuth(user, password).
|
||||
SetHeader("Content-Length", fmt.Sprintf("%d", len(blob))).
|
||||
SetHeader("Content-Type", "application/octet-stream").
|
||||
SetQueryParam("digest", digest).
|
||||
SetBody(blob).
|
||||
Put(baseURL + loc)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode() != http.StatusCreated {
|
||||
return ErrPutBlob
|
||||
}
|
||||
}
|
||||
// upload config
|
||||
cblob, err := json.Marshal(img.Config)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cdigest := godigest.FromBytes(cblob)
|
||||
|
||||
if img.Manifest.Config.MediaType == ispec.MediaTypeEmptyJSON {
|
||||
cblob = ispec.DescriptorEmptyJSON.Data
|
||||
cdigest = ispec.DescriptorEmptyJSON.Digest
|
||||
}
|
||||
|
||||
resp, err := resty.R().
|
||||
SetBasicAuth(user, password).
|
||||
Post(baseURL + "/v2/" + repo + "/blobs/uploads/")
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if inject.ErrStatusCode(resp.StatusCode()) != http.StatusAccepted || inject.ErrStatusCode(resp.StatusCode()) == -1 {
|
||||
return ErrPostBlob
|
||||
}
|
||||
|
||||
loc := Location(baseURL, resp)
|
||||
|
||||
// uploading blob should get 201
|
||||
resp, err = resty.R().
|
||||
SetBasicAuth(user, password).
|
||||
SetHeader("Content-Length", fmt.Sprintf("%d", len(cblob))).
|
||||
SetHeader("Content-Type", "application/octet-stream").
|
||||
SetQueryParam("digest", cdigest.String()).
|
||||
SetBody(cblob).
|
||||
Put(loc)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if inject.ErrStatusCode(resp.StatusCode()) != http.StatusCreated || inject.ErrStatusCode(resp.StatusCode()) == -1 {
|
||||
return ErrPostBlob
|
||||
}
|
||||
|
||||
// put manifest
|
||||
manifestBlob, err := json.Marshal(img.Manifest)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = resty.R().
|
||||
SetBasicAuth(user, password).
|
||||
SetHeader("Content-type", "application/vnd.oci.image.manifest.v1+json").
|
||||
SetBody(manifestBlob).
|
||||
Put(baseURL + "/v2/" + repo + "/manifests/" + ref)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func SignImageUsingCosign(repoTag, port string) error {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
@ -1900,7 +2031,7 @@ func GetRandomMultiarchImage(reference string) (MultiarchImage, error) {
|
||||
}, err
|
||||
}
|
||||
|
||||
func GetMultiarchImageForImages(reference string, images []Image) MultiarchImage {
|
||||
func GetMultiarchImageForImages(images []Image) MultiarchImage {
|
||||
var index ispec.Index
|
||||
|
||||
for i, image := range images {
|
||||
@ -1916,7 +2047,7 @@ func GetMultiarchImageForImages(reference string, images []Image) MultiarchImage
|
||||
|
||||
index.SchemaVersion = 2
|
||||
|
||||
return MultiarchImage{Index: index, Images: images, Reference: reference}
|
||||
return MultiarchImage{Index: index, Images: images}
|
||||
}
|
||||
|
||||
func getManifestSize(manifest ispec.Manifest) int64 {
|
||||
@ -1968,6 +2099,37 @@ func UploadMultiarchImage(multiImage MultiarchImage, baseURL string, repo string
|
||||
return err
|
||||
}
|
||||
|
||||
func UploadMultiarchImageWithRef(multiImage MultiarchImage, baseURL string, repo, ref string) error {
|
||||
for _, image := range multiImage.Images {
|
||||
err := UploadImageWithRef(image, baseURL, repo, image.DigestStr())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// put manifest
|
||||
indexBlob, err := json.Marshal(multiImage.Index)
|
||||
if err = inject.Error(err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// validate manifest
|
||||
if err := storageCommon.ValidateImageIndexSchema(indexBlob); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := resty.R().
|
||||
SetHeader("Content-type", ispec.MediaTypeImageIndex).
|
||||
SetBody(indexBlob).
|
||||
Put(baseURL + "/v2/" + repo + "/manifests/" + ref)
|
||||
|
||||
if resp.StatusCode() != http.StatusCreated {
|
||||
return ErrPutIndex
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func GetIndexBlobWithManifests(manifestDigests []godigest.Digest) ([]byte, error) {
|
||||
manifests := make([]ispec.Descriptor, 0, len(manifestDigests))
|
||||
|
||||
@ -2037,3 +2199,87 @@ func CustomRedirectPolicy(noOfRedirect int) resty.RedirectPolicy {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func DateRef(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) *time.Time {
|
||||
date := time.Date(year, month, day, hour, min, sec, nsec, loc)
|
||||
|
||||
return &date
|
||||
}
|
||||
|
||||
func RandomDateRef(loc *time.Location) *time.Time {
|
||||
var (
|
||||
year = 1990 + mathRand.Intn(30) //nolint: gosec,gomnd
|
||||
month = time.Month(1 + mathRand.Intn(10)) //nolint: gosec,gomnd
|
||||
day = 1 + mathRand.Intn(5) //nolint: gosec,gomnd
|
||||
hour = 1 + mathRand.Intn(22) //nolint: gosec,gomnd
|
||||
min = 1 + mathRand.Intn(58) //nolint: gosec,gomnd
|
||||
sec = 1 + mathRand.Intn(58) //nolint: gosec,gomnd
|
||||
nsec = 1
|
||||
)
|
||||
|
||||
return DateRef(year, month, day, hour, min, sec, nsec, time.UTC)
|
||||
}
|
||||
|
||||
func GetDefaultConfig() ispec.Image {
|
||||
return ispec.Image{
|
||||
Created: DefaultTimeRef(),
|
||||
Author: "ZotUser",
|
||||
Platform: ispec.Platform{
|
||||
OS: "linux",
|
||||
Architecture: "amd64",
|
||||
},
|
||||
RootFS: ispec.RootFS{
|
||||
Type: "layers",
|
||||
DiffIDs: []godigest.Digest{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func GetDefaultVulnConfig() ispec.Image {
|
||||
return ispec.Image{
|
||||
Created: DefaultTimeRef(),
|
||||
Author: "ZotUser",
|
||||
Platform: ispec.Platform{
|
||||
Architecture: "amd64",
|
||||
OS: "linux",
|
||||
},
|
||||
Config: ispec.ImageConfig{
|
||||
Env: []string{"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"},
|
||||
Cmd: []string{"/bin/sh"},
|
||||
},
|
||||
RootFS: ispec.RootFS{
|
||||
Type: "layers",
|
||||
DiffIDs: []godigest.Digest{"sha256:f1417ff83b319fbdae6dd9cd6d8c9c88002dcd75ecf6ec201c8c6894681cf2b5"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultTimeRef() *time.Time {
|
||||
var (
|
||||
year = 2010
|
||||
month = time.Month(1)
|
||||
day = 1
|
||||
hour = 1
|
||||
min = 1
|
||||
sec = 1
|
||||
nsec = 0
|
||||
)
|
||||
|
||||
return DateRef(year, month, day, hour, min, sec, nsec, time.UTC)
|
||||
}
|
||||
|
||||
func GetDefaultLayers() []Layer {
|
||||
return []Layer{
|
||||
{Blob: []byte("abc"), Digest: godigest.FromBytes([]byte("abc")), MediaType: ispec.MediaTypeImageLayerGzip},
|
||||
{Blob: []byte("123"), Digest: godigest.FromBytes([]byte("123")), MediaType: ispec.MediaTypeImageLayerGzip},
|
||||
{Blob: []byte("xyz"), Digest: godigest.FromBytes([]byte("xyz")), MediaType: ispec.MediaTypeImageLayerGzip},
|
||||
}
|
||||
}
|
||||
|
||||
func GetDefaultLayersBlobs() [][]byte {
|
||||
return [][]byte{
|
||||
[]byte("abc"),
|
||||
[]byte("123"),
|
||||
[]byte("xyz"),
|
||||
}
|
||||
}
|
||||
|
@ -661,17 +661,29 @@ func TestUploadImage(t *testing.T) {
|
||||
Convey("Request fail while pushing layer", func() {
|
||||
err := test.UploadImageWithBasicAuth(test.Image{Layers: [][]byte{{1, 2, 3}}}, "badURL", "", "", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
err = test.UploadImageWithBasicAuthRef(test.Image{Layers: [][]byte{{1, 2, 3}}}, "badURL", "", "", "", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
Convey("Request status is not StatusOk while pushing layer", func() {
|
||||
err := test.UploadImageWithBasicAuth(test.Image{Layers: [][]byte{{1, 2, 3}}}, baseURL, "repo", "", "")
|
||||
err := test.UploadImageWithBasicAuth(test.Image{Layers: [][]byte{{1, 2, 3}}}, baseURL, "", "repo", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
err = test.UploadImageWithBasicAuthRef(test.Image{Layers: [][]byte{{1, 2, 3}}}, baseURL, "", "repo", "", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
Convey("Request fail while pushing config", func() {
|
||||
err := test.UploadImageWithBasicAuth(test.Image{}, "badURL", "", "", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
err = test.UploadImageWithBasicAuthRef(test.Image{}, "badURL", "", "", "", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
Convey("Request status is not StatusOk while pushing config", func() {
|
||||
err := test.UploadImageWithBasicAuth(test.Image{}, baseURL, "repo", "", "")
|
||||
err := test.UploadImageWithBasicAuth(test.Image{}, baseURL, "", "repo", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
err = test.UploadImageWithBasicAuthRef(test.Image{}, baseURL, "", "repo", "", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
@ -819,6 +831,9 @@ func TestInjectUploadImage(t *testing.T) {
|
||||
if injected {
|
||||
err := test.UploadImage(img, baseURL, "test")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
err = test.UploadImageWithRef(img, baseURL, "test", img.DigestStr())
|
||||
So(err, ShouldNotBeNil)
|
||||
}
|
||||
})
|
||||
Convey("CreateBlobUpload POST call", func() {
|
||||
@ -826,6 +841,9 @@ func TestInjectUploadImage(t *testing.T) {
|
||||
if injected {
|
||||
err := test.UploadImage(img, baseURL, "test")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
err = test.UploadImageWithRef(img, baseURL, "test", img.DigestStr())
|
||||
So(err, ShouldNotBeNil)
|
||||
}
|
||||
})
|
||||
Convey("UpdateBlobUpload PUT call", func() {
|
||||
@ -833,6 +851,9 @@ func TestInjectUploadImage(t *testing.T) {
|
||||
if injected {
|
||||
err := test.UploadImage(img, baseURL, "test")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
err = test.UploadImageWithRef(img, baseURL, "test", img.DigestStr())
|
||||
So(err, ShouldNotBeNil)
|
||||
}
|
||||
})
|
||||
Convey("second marshal", func() {
|
||||
@ -840,6 +861,9 @@ func TestInjectUploadImage(t *testing.T) {
|
||||
if injected {
|
||||
err := test.UploadImage(img, baseURL, "test")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
err = test.UploadImageWithRef(img, baseURL, "test", img.DigestStr())
|
||||
So(err, ShouldNotBeNil)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
478
pkg/test/images.go
Normal file
478
pkg/test/images.go
Normal file
@ -0,0 +1,478 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
mathRand "math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
"github.com/opencontainers/image-spec/specs-go"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
storageConstants "zotregistry.io/zot/pkg/storage/constants"
|
||||
)
|
||||
|
||||
// LayerBuilder abstracts the first step in creating an OCI image, specifying the layers of the image.
|
||||
type LayerBuilder interface {
|
||||
// LayerBlobs sets the image layers from the gives blobs array, adding a default zipped layer media type.
|
||||
LayerBlobs(layers [][]byte) ConfigBuilder
|
||||
// Layers sets the given layers to the built image
|
||||
Layers(layers []Layer) ConfigBuilder
|
||||
// RandomLayers generates `count` layers with the given size and initialises them with random values
|
||||
// and a default zipped layer media type.
|
||||
RandomLayers(count, size int) ConfigBuilder
|
||||
// EmptyLayer adds a single empty json layer semnifying no layers.
|
||||
EmptyLayer() ConfigBuilder
|
||||
// DefaultLayers adds predefined default layers.
|
||||
DefaultLayers() ConfigBuilder
|
||||
// VulnerableLayers adds layers that contains known CVE's.
|
||||
VulnerableLayers() VulnerableConfigBuilder
|
||||
}
|
||||
|
||||
// ConfigBuilder abstracts the second step in creating an OCI image, specifying the config content of the image.
|
||||
type ConfigBuilder interface {
|
||||
// ImageConfig sets the given image config. It updates the "config" field of the image manifest with
|
||||
// values corresponding to the given image.
|
||||
ImageConfig(config ispec.Image) ManifestBuilder
|
||||
// ImageConfig sets an empty json as the images config. It updates the "config" field of the image manifest with
|
||||
// values corresponding to the empty descriptor.
|
||||
EmptyConfig() ManifestBuilder
|
||||
// ArtifactConfig sets an empty json as the content of the image config and sets it's media type (described by
|
||||
// the Config field of the image manifest) to the given artifact type. This will make the created image
|
||||
// an OCI artifact.
|
||||
// (see: https://github.com/opencontainers/image-spec/blob/main/manifest.md#guidelines-for-artifact-usage)
|
||||
ArtifactConfig(artifactType string) ManifestBuilder
|
||||
// DefaultConfig sets the default config, platform linux/amd64.
|
||||
DefaultConfig() ManifestBuilder
|
||||
// RandomConfig sets a randomly generated config.
|
||||
RandomConfig() ManifestBuilder
|
||||
}
|
||||
|
||||
// VulnerableConfigBuilder abstracts specifying the config of an vulnerage OCI image.
|
||||
// Keeping the RootFS field consistent with the vulnerable layers.
|
||||
type VulnerableConfigBuilder interface {
|
||||
// VulnerableConfig sets the given config while keeping the correct RootFS values for the
|
||||
// vulnerable layer set earlier. This allows scan tools to find CVE's
|
||||
VulnerableConfig(config ispec.Image) ManifestBuilder
|
||||
// DefaultVulnConfig sets default config of the vulnerable image
|
||||
DefaultVulnConfig() ManifestBuilder
|
||||
// RandomVulnConfig sets the keeping the correct RootFS values for the
|
||||
// vulnerable layer set earlier. This allows scan tools to find CVE's
|
||||
RandomVulnConfig() ManifestBuilder
|
||||
}
|
||||
|
||||
// ManifestBuilder abstracts creating the manifest of the image.
|
||||
type ManifestBuilder interface {
|
||||
// Subject sets the subject of the image manifest.
|
||||
Subject(subject *ispec.Descriptor) ManifestBuilder
|
||||
// ArtifactType sets the artifact type field on the image manifest,
|
||||
// (see: https://github.com/opencontainers/image-spec/blob/main/manifest.md#guidelines-for-artifact-usage)
|
||||
ArtifactType(artifactType string) ManifestBuilder
|
||||
// Annotations sets the annotations field on the image manifest.
|
||||
Annotations(annotations map[string]string) ManifestBuilder
|
||||
|
||||
Build() Image
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
Manifest ispec.Manifest
|
||||
Config ispec.Image
|
||||
Layers [][]byte
|
||||
Reference string
|
||||
|
||||
ConfigDescriptor ispec.Descriptor
|
||||
ManifestDescriptor ispec.Descriptor
|
||||
}
|
||||
|
||||
func (img *Image) Digest() godigest.Digest {
|
||||
blob, err := json.Marshal(img.Manifest)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Manifest should always be marshable")
|
||||
}
|
||||
|
||||
// when we'll migrate all code to the new format of creating images we can replace this with
|
||||
// the value from manifestDescriptor
|
||||
return godigest.FromBytes(blob)
|
||||
}
|
||||
|
||||
func (img *Image) DigestStr() string {
|
||||
return img.Digest().String()
|
||||
}
|
||||
|
||||
func (img Image) Descriptor() ispec.Descriptor {
|
||||
return ispec.Descriptor{
|
||||
MediaType: img.ManifestDescriptor.MediaType,
|
||||
Digest: img.ManifestDescriptor.Digest,
|
||||
Size: img.ManifestDescriptor.Size,
|
||||
}
|
||||
}
|
||||
|
||||
func (img Image) DescriptorRef() *ispec.Descriptor {
|
||||
return &ispec.Descriptor{
|
||||
MediaType: img.ManifestDescriptor.MediaType,
|
||||
Digest: img.ManifestDescriptor.Digest,
|
||||
Size: img.ManifestDescriptor.Size,
|
||||
}
|
||||
}
|
||||
|
||||
type Layer struct {
|
||||
Blob []byte
|
||||
MediaType string
|
||||
Digest godigest.Digest
|
||||
}
|
||||
|
||||
// CreateImageWith initiates the creation of an OCI image. The creation process starts with
|
||||
// specifying the layers of the image.
|
||||
func CreateImageWith() LayerBuilder {
|
||||
// set default values here
|
||||
return &BaseImageBuilder{}
|
||||
}
|
||||
|
||||
func CreateDefaultImage() Image {
|
||||
return CreateImageWith().DefaultLayers().DefaultConfig().Build()
|
||||
}
|
||||
|
||||
func CreateDefaultImageWith() ManifestBuilder {
|
||||
return CreateImageWith().DefaultLayers().DefaultConfig()
|
||||
}
|
||||
|
||||
const (
|
||||
layerCount = 1
|
||||
layerSize = 10
|
||||
)
|
||||
|
||||
func CreateRandomImage() Image {
|
||||
return CreateImageWith().RandomLayers(layerCount, layerSize).RandomConfig().Build()
|
||||
}
|
||||
|
||||
func CreateRandomImageWith() ManifestBuilder {
|
||||
return CreateImageWith().RandomLayers(layerCount, layerSize).RandomConfig()
|
||||
}
|
||||
|
||||
func CreateVulnerableImage() Image {
|
||||
return CreateImageWith().VulnerableLayers().DefaultVulnConfig().Build()
|
||||
}
|
||||
|
||||
func CreateRandomVulnerableImage() Image {
|
||||
return CreateImageWith().VulnerableLayers().RandomVulnConfig().Build()
|
||||
}
|
||||
|
||||
func CreateRandomVulnerableImageWith() ManifestBuilder {
|
||||
return CreateImageWith().VulnerableLayers().RandomVulnConfig()
|
||||
}
|
||||
|
||||
type BaseImageBuilder struct {
|
||||
layers []Layer
|
||||
|
||||
config ispec.Image
|
||||
configDescriptor ispec.Descriptor
|
||||
|
||||
annotations map[string]string
|
||||
subject *ispec.Descriptor
|
||||
artifactType string
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) Layers(layers []Layer) ConfigBuilder {
|
||||
ib.layers = layers
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) LayerBlobs(layers [][]byte) ConfigBuilder {
|
||||
for _, layer := range layers {
|
||||
ib.layers = append(ib.layers, Layer{
|
||||
Blob: layer,
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
Digest: godigest.FromBytes(layer),
|
||||
})
|
||||
}
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) EmptyLayer() ConfigBuilder {
|
||||
ib.layers = []Layer{
|
||||
{
|
||||
Blob: ispec.DescriptorEmptyJSON.Data,
|
||||
MediaType: ispec.DescriptorEmptyJSON.MediaType,
|
||||
Digest: ispec.DescriptorEmptyJSON.Digest,
|
||||
},
|
||||
}
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) RandomLayers(count, size int) ConfigBuilder {
|
||||
for i := 0; i < count; i++ {
|
||||
layer := make([]byte, size)
|
||||
|
||||
_, err := rand.Read(layer)
|
||||
if err != nil {
|
||||
panic("unexpected error while reading random bytes")
|
||||
}
|
||||
|
||||
ib.layers = append(ib.layers, Layer{
|
||||
Blob: layer,
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
Digest: godigest.FromBytes(layer),
|
||||
})
|
||||
}
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) DefaultLayers() ConfigBuilder {
|
||||
ib.layers = GetDefaultLayers()
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) VulnerableLayers() VulnerableConfigBuilder {
|
||||
layer, err := GetLayerWithVulnerability()
|
||||
if err != nil {
|
||||
panic("unable to read vulnerable layers from test data: " + err.Error())
|
||||
}
|
||||
|
||||
ib.layers = []Layer{
|
||||
{
|
||||
Blob: layer,
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
Digest: godigest.FromBytes(layer),
|
||||
},
|
||||
}
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) ImageConfig(config ispec.Image) ManifestBuilder {
|
||||
ib.config = config
|
||||
|
||||
configBlob, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Image should always be marshable")
|
||||
}
|
||||
|
||||
ib.configDescriptor = ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
}
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) DefaultConfig() ManifestBuilder {
|
||||
return ib.ImageConfig(GetDefaultConfig())
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) EmptyConfig() ManifestBuilder {
|
||||
ib.configDescriptor = ispec.DescriptorEmptyJSON
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) ArtifactConfig(artifactType string) ManifestBuilder {
|
||||
configDescriptor := ispec.DescriptorEmptyJSON
|
||||
configDescriptor.MediaType = artifactType
|
||||
|
||||
ib.configDescriptor = configDescriptor
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) RandomConfig() ManifestBuilder {
|
||||
config := GetDefaultConfig()
|
||||
config.Author = getRandomAuthor()
|
||||
config.Platform = getRandomPlatform()
|
||||
config.Created = RandomDateRef(time.UTC)
|
||||
|
||||
ib.config = config
|
||||
|
||||
configBlob, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Image should always be marshable")
|
||||
}
|
||||
|
||||
ib.configDescriptor = ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
}
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) DefaultVulnConfig() ManifestBuilder {
|
||||
vulnerableConfig := GetDefaultVulnConfig()
|
||||
|
||||
configBlob, err := json.Marshal(vulnerableConfig)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Image should always be marshable")
|
||||
}
|
||||
|
||||
vulnConfigDescriptor := ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
}
|
||||
|
||||
ib.config = vulnerableConfig
|
||||
ib.configDescriptor = vulnConfigDescriptor
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) VulnerableConfig(config ispec.Image) ManifestBuilder {
|
||||
vulnerableConfig := ispec.Image{
|
||||
Created: config.Created,
|
||||
Platform: config.Platform,
|
||||
Config: config.Config,
|
||||
RootFS: ispec.RootFS{
|
||||
Type: "layers",
|
||||
DiffIDs: []godigest.Digest{"sha256:f1417ff83b319fbdae6dd9cd6d8c9c88002dcd75ecf6ec201c8c6894681cf2b5"},
|
||||
},
|
||||
Author: config.Author,
|
||||
History: config.History,
|
||||
}
|
||||
|
||||
configBlob, err := json.Marshal(vulnerableConfig)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Image should always be marshable")
|
||||
}
|
||||
|
||||
vulnConfigDescriptor := ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
}
|
||||
|
||||
ib.config = vulnerableConfig
|
||||
ib.configDescriptor = vulnConfigDescriptor
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) RandomVulnConfig() ManifestBuilder {
|
||||
vulnerableConfig := GetDefaultVulnConfig()
|
||||
|
||||
vulnerableConfig.Author = getRandomAuthor()
|
||||
vulnerableConfig.Platform = getRandomPlatform()
|
||||
vulnerableConfig.Created = RandomDateRef(time.UTC)
|
||||
|
||||
configBlob, err := json.Marshal(vulnerableConfig)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Image should always be marshable")
|
||||
}
|
||||
|
||||
vulnConfigDescriptor := ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
}
|
||||
|
||||
ib.config = vulnerableConfig
|
||||
ib.configDescriptor = vulnConfigDescriptor
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) Subject(subject *ispec.Descriptor) ManifestBuilder {
|
||||
ib.subject = subject
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) ArtifactType(artifactType string) ManifestBuilder {
|
||||
ib.artifactType = artifactType
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) Annotations(annotations map[string]string) ManifestBuilder {
|
||||
ib.annotations = annotations
|
||||
|
||||
return ib
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) Build() Image {
|
||||
img := Image{
|
||||
Layers: getLayerBlobs(ib.layers),
|
||||
Config: ib.config,
|
||||
ConfigDescriptor: ib.configDescriptor,
|
||||
Manifest: ispec.Manifest{
|
||||
Versioned: specs.Versioned{SchemaVersion: storageConstants.SchemaVersion},
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Config: ispec.Descriptor{
|
||||
MediaType: ib.configDescriptor.MediaType,
|
||||
Digest: ib.configDescriptor.Digest,
|
||||
Size: ib.configDescriptor.Size,
|
||||
},
|
||||
Layers: getLayersDescriptors(ib.layers),
|
||||
ArtifactType: ib.artifactType,
|
||||
Subject: ib.subject,
|
||||
Annotations: ib.annotations,
|
||||
},
|
||||
}
|
||||
|
||||
manifestBlob, err := json.Marshal(img.Manifest)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Manifest should always be marshable")
|
||||
}
|
||||
|
||||
img.ManifestDescriptor = ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: godigest.FromBytes(manifestBlob),
|
||||
Size: int64(len(manifestBlob)),
|
||||
Data: manifestBlob,
|
||||
}
|
||||
|
||||
img.Reference = img.ManifestDescriptor.Digest.String()
|
||||
|
||||
return img
|
||||
}
|
||||
|
||||
func getRandomAuthor() string {
|
||||
const n = 100000
|
||||
|
||||
return "ZotUser-" + strconv.Itoa(mathRand.Intn(n)) //nolint: gosec
|
||||
}
|
||||
|
||||
func getRandomPlatform() ispec.Platform {
|
||||
const n = 100000
|
||||
|
||||
return ispec.Platform{
|
||||
OS: "linux-" + strconv.Itoa(mathRand.Intn(n)), //nolint: gosec
|
||||
Architecture: "amd64-" + strconv.Itoa(mathRand.Intn(n)), //nolint: gosec
|
||||
}
|
||||
}
|
||||
|
||||
func getLayerBlobs(layers []Layer) [][]byte {
|
||||
blobs := make([][]byte, len(layers))
|
||||
|
||||
for i := range layers {
|
||||
blobs[i] = layers[i].Blob
|
||||
}
|
||||
|
||||
return blobs
|
||||
}
|
||||
|
||||
func getLayersDescriptors(layers []Layer) []ispec.Descriptor {
|
||||
descriptors := make([]ispec.Descriptor, len(layers))
|
||||
|
||||
for i := range layers {
|
||||
descriptors[i] = ispec.Descriptor{
|
||||
Digest: layers[i].Digest,
|
||||
MediaType: layers[i].MediaType,
|
||||
Size: int64(len(layers[i].Blob)),
|
||||
}
|
||||
}
|
||||
|
||||
return descriptors
|
||||
}
|
200
pkg/test/images_test.go
Normal file
200
pkg/test/images_test.go
Normal file
@ -0,0 +1,200 @@
|
||||
package test_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"zotregistry.io/zot/pkg/test"
|
||||
)
|
||||
|
||||
func TestImageBuilder(t *testing.T) {
|
||||
vulnLayer, err := test.GetLayerWithVulnerability()
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
Convey("Test Layer Builders", t, func() {
|
||||
layerBuilder := test.CreateImageWith()
|
||||
|
||||
Convey("LayerBlobs", func() {
|
||||
layerBlobs := [][]byte{{11, 11, 11}, {22, 22, 22}}
|
||||
|
||||
image := layerBuilder.
|
||||
LayerBlobs(layerBlobs).
|
||||
DefaultConfig().
|
||||
Build()
|
||||
|
||||
So(image.Layers, ShouldResemble, layerBlobs)
|
||||
So(image.Config, ShouldResemble, test.GetDefaultConfig())
|
||||
})
|
||||
|
||||
Convey("DefaultLayers", func() {
|
||||
image := layerBuilder.
|
||||
DefaultLayers().
|
||||
DefaultConfig().
|
||||
Build()
|
||||
|
||||
So(image.Layers, ShouldResemble, test.GetDefaultLayersBlobs())
|
||||
So(image.Config, ShouldResemble, test.GetDefaultConfig())
|
||||
})
|
||||
|
||||
Convey("Layers", func() {
|
||||
blob1, blob2 := []byte{10, 10, 10}, []byte{20, 20, 20}
|
||||
|
||||
layers := []test.Layer{
|
||||
{
|
||||
Blob: blob1,
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
Digest: godigest.FromBytes(blob1),
|
||||
},
|
||||
{
|
||||
Blob: blob2,
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
Digest: godigest.FromBytes(blob2),
|
||||
},
|
||||
}
|
||||
image := layerBuilder.
|
||||
Layers(layers).
|
||||
DefaultConfig().
|
||||
Build()
|
||||
|
||||
So(image.Layers, ShouldResemble, [][]byte{blob1, blob2})
|
||||
So(image.Config, ShouldResemble, test.GetDefaultConfig())
|
||||
})
|
||||
|
||||
Convey("Empty Layer", func() {
|
||||
image := layerBuilder.
|
||||
EmptyLayer().
|
||||
DefaultConfig().
|
||||
Build()
|
||||
|
||||
So(image.Layers, ShouldResemble, [][]byte{ispec.DescriptorEmptyJSON.Data})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Config builder", t, func() {
|
||||
configBuilder := test.CreateImageWith().DefaultLayers()
|
||||
|
||||
Convey("Empty Config", func() {
|
||||
img := configBuilder.EmptyConfig().Build()
|
||||
So(img.Manifest.Config.Size, ShouldEqual, ispec.DescriptorEmptyJSON.Size)
|
||||
So(img.Manifest.Config.Digest, ShouldResemble, ispec.DescriptorEmptyJSON.Digest)
|
||||
So(img.Reference, ShouldResemble, img.Digest().String())
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Vulnerable config builder", t, func() {
|
||||
configBuilder := test.CreateImageWith().VulnerableLayers()
|
||||
|
||||
Convey("VulnerableConfig", func() {
|
||||
platform := ispec.Platform{OS: "os", Architecture: "arch"}
|
||||
|
||||
img := configBuilder.VulnerableConfig(ispec.Image{
|
||||
Platform: ispec.Platform{OS: "os", Architecture: "arch"},
|
||||
}).Build()
|
||||
|
||||
So(img.Layers[0], ShouldEqual, vulnLayer)
|
||||
So(img.Config.Platform, ShouldResemble, platform)
|
||||
})
|
||||
|
||||
Convey("Random VulnerableConfig", func() {
|
||||
img := configBuilder.RandomVulnConfig().Build()
|
||||
|
||||
So(img.Layers[0], ShouldEqual, vulnLayer)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Manifes builder", t, func() {
|
||||
manifestBuilder := test.CreateImageWith().DefaultLayers().DefaultConfig()
|
||||
|
||||
subject := ispec.Descriptor{
|
||||
Digest: godigest.FromString("digest"),
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
}
|
||||
|
||||
image := manifestBuilder.
|
||||
Subject(&subject).
|
||||
ArtifactType("art.type").
|
||||
Annotations(map[string]string{"key": "val"}).
|
||||
Build()
|
||||
|
||||
So(image.Layers, ShouldResemble, test.GetDefaultLayersBlobs())
|
||||
So(image.Config, ShouldResemble, test.GetDefaultConfig())
|
||||
So(image.Manifest.Subject, ShouldResemble, &subject)
|
||||
So(image.Manifest.ArtifactType, ShouldResemble, "art.type")
|
||||
So(image.Manifest.Annotations, ShouldResemble, map[string]string{"key": "val"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestMultiarchImageBuilder(t *testing.T) {
|
||||
Convey("Multiarch", t, func() {
|
||||
multiArch := test.CreateMultiarchWith().
|
||||
Images([]test.Image{
|
||||
test.CreateRandomImage(),
|
||||
test.CreateRandomImage(),
|
||||
}).
|
||||
Annotations(map[string]string{"a": "b"}).
|
||||
ArtifactType("art.type").
|
||||
Subject(&ispec.Descriptor{}).
|
||||
Build()
|
||||
|
||||
So(len(multiArch.Images), ShouldEqual, 2)
|
||||
So(multiArch.Index.ArtifactType, ShouldResemble, "art.type")
|
||||
So(multiArch.Index.Subject, ShouldNotBeNil)
|
||||
So(multiArch.Index.Annotations, ShouldNotBeNil)
|
||||
So(multiArch.Index.Annotations, ShouldContainKey, "a")
|
||||
})
|
||||
}
|
||||
|
||||
func TestPredefinedImages(t *testing.T) {
|
||||
Convey("Predefined Images", t, func() {
|
||||
img := test.CreateDefaultImage()
|
||||
So(img.Layers, ShouldResemble, test.GetDefaultLayersBlobs())
|
||||
|
||||
img = test.CreateDefaultImageWith().ArtifactType("art.type").Build()
|
||||
So(img.Manifest.ArtifactType, ShouldEqual, "art.type")
|
||||
|
||||
img = test.CreateRandomImageWith().ArtifactType("art.type").Build()
|
||||
So(img.Manifest.ArtifactType, ShouldEqual, "art.type")
|
||||
|
||||
img = test.CreateRandomVulnerableImage()
|
||||
So(img.Layers, ShouldNotResemble, test.GetDefaultLayersBlobs())
|
||||
|
||||
img = test.CreateRandomVulnerableImageWith().ArtifactType("art.type").Build()
|
||||
So(img.Manifest.ArtifactType, ShouldEqual, "art.type")
|
||||
})
|
||||
|
||||
Convey("Predefined Multiarch-Images", t, func() {
|
||||
multiArch := test.CreateRandomMultiarch()
|
||||
So(len(multiArch.Images), ShouldEqual, 3)
|
||||
So(multiArch.Reference, ShouldResemble, multiArch.Digest().String())
|
||||
|
||||
multiArch = test.CreateVulnerableMultiarch()
|
||||
So(len(multiArch.Images), ShouldEqual, 3)
|
||||
So(multiArch.Reference, ShouldResemble, multiArch.Digest().String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestImageMethods(t *testing.T) {
|
||||
img := test.CreateDefaultImage()
|
||||
|
||||
Convey("Image", t, func() {
|
||||
manifestBlob, err := json.Marshal(img.Manifest)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
manifestDigest := godigest.FromBytes(manifestBlob)
|
||||
manifestSize := int64(len(manifestBlob))
|
||||
|
||||
Convey("img descriptor", func() {
|
||||
descriptor := img.Descriptor()
|
||||
|
||||
So(manifestDigest, ShouldResemble, descriptor.Digest)
|
||||
So(manifestSize, ShouldEqual, descriptor.Size)
|
||||
So(ispec.MediaTypeImageManifest, ShouldResemble, descriptor.MediaType)
|
||||
})
|
||||
})
|
||||
}
|
147
pkg/test/multiarch.go
Normal file
147
pkg/test/multiarch.go
Normal file
@ -0,0 +1,147 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
godigest "github.com/opencontainers/go-digest"
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
||||
mTypes "zotregistry.io/zot/pkg/meta/types"
|
||||
)
|
||||
|
||||
type MultiarchImage struct {
|
||||
Index ispec.Index
|
||||
Images []Image
|
||||
Reference string
|
||||
|
||||
indexDescriptor ispec.Descriptor
|
||||
}
|
||||
|
||||
func (mi *MultiarchImage) Digest() godigest.Digest {
|
||||
indexBlob, err := json.Marshal(mi.Index)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Index should always be marshable")
|
||||
}
|
||||
|
||||
return godigest.FromBytes(indexBlob)
|
||||
}
|
||||
|
||||
func (mi *MultiarchImage) DigestStr() string {
|
||||
return mi.Digest().String()
|
||||
}
|
||||
|
||||
func (mi *MultiarchImage) IndexData() mTypes.IndexData {
|
||||
indexBlob, err := json.Marshal(mi.Index)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Index should always be marshable")
|
||||
}
|
||||
|
||||
return mTypes.IndexData{IndexBlob: indexBlob}
|
||||
}
|
||||
|
||||
type ImagesBuilder interface {
|
||||
Images(images []Image) MultiarchBuilder
|
||||
}
|
||||
|
||||
type MultiarchBuilder interface {
|
||||
Subject(subject *ispec.Descriptor) MultiarchBuilder
|
||||
ArtifactType(artifactType string) MultiarchBuilder
|
||||
Annotations(annotations map[string]string) MultiarchBuilder
|
||||
Build() MultiarchImage
|
||||
}
|
||||
|
||||
func CreateMultiarchWith() ImagesBuilder {
|
||||
return &BaseMultiarchBuilder{}
|
||||
}
|
||||
|
||||
func CreateRandomMultiarch() MultiarchImage {
|
||||
return CreateMultiarchWith().
|
||||
Images([]Image{
|
||||
CreateRandomImage(),
|
||||
CreateRandomImage(),
|
||||
CreateRandomImage(),
|
||||
}).
|
||||
Build()
|
||||
}
|
||||
|
||||
func CreateVulnerableMultiarch() MultiarchImage {
|
||||
return CreateMultiarchWith().
|
||||
Images([]Image{
|
||||
CreateRandomImage(),
|
||||
CreateRandomVulnerableImage(),
|
||||
CreateRandomImage(),
|
||||
}).
|
||||
Build()
|
||||
}
|
||||
|
||||
type BaseMultiarchBuilder struct {
|
||||
images []Image
|
||||
subject *ispec.Descriptor
|
||||
artifactType string
|
||||
annotations map[string]string
|
||||
}
|
||||
|
||||
func (mb *BaseMultiarchBuilder) Images(images []Image) MultiarchBuilder {
|
||||
mb.images = images
|
||||
|
||||
return mb
|
||||
}
|
||||
|
||||
func (mb *BaseMultiarchBuilder) Subject(subject *ispec.Descriptor) MultiarchBuilder {
|
||||
mb.subject = subject
|
||||
|
||||
return mb
|
||||
}
|
||||
|
||||
func (mb *BaseMultiarchBuilder) ArtifactType(artifactType string) MultiarchBuilder {
|
||||
mb.artifactType = artifactType
|
||||
|
||||
return mb
|
||||
}
|
||||
|
||||
func (mb *BaseMultiarchBuilder) Annotations(annotations map[string]string) MultiarchBuilder {
|
||||
mb.annotations = annotations
|
||||
|
||||
return mb
|
||||
}
|
||||
|
||||
func (mb *BaseMultiarchBuilder) Build() MultiarchImage {
|
||||
manifests := make([]ispec.Descriptor, len(mb.images))
|
||||
|
||||
for i := range manifests {
|
||||
manifests[i] = ispec.Descriptor{
|
||||
Digest: mb.images[i].ManifestDescriptor.Digest,
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
}
|
||||
}
|
||||
|
||||
index := ispec.Index{
|
||||
MediaType: ispec.MediaTypeImageIndex,
|
||||
Manifests: manifests,
|
||||
Annotations: mb.annotations,
|
||||
Subject: mb.subject,
|
||||
ArtifactType: mb.artifactType,
|
||||
}
|
||||
|
||||
indexBlob, err := json.Marshal(index)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Index should always be marshable")
|
||||
}
|
||||
|
||||
indexDigest := godigest.FromBytes(indexBlob)
|
||||
|
||||
ref := indexDigest.String()
|
||||
|
||||
return MultiarchImage{
|
||||
Index: index,
|
||||
Images: mb.images,
|
||||
Reference: ref,
|
||||
|
||||
indexDescriptor: ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageIndex,
|
||||
Size: int64(len(indexBlob)),
|
||||
Digest: indexDigest,
|
||||
Data: indexBlob,
|
||||
},
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user