feat(test): added image builder for use in tests (#1583)

Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
LaurentiuNiculae 2023-07-26 13:08:04 +03:00 committed by GitHub
parent 4194489868
commit abba6aa3cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1421 additions and 423 deletions

View File

@ -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)

View File

@ -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)
}

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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,

View File

@ -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"),
}
}

View File

@ -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
View 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
View 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
View 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,
},
}
}