2021-10-05 04:12:22 -05:00
|
|
|
package storage_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2023-09-05 11:48:56 -05:00
|
|
|
"context"
|
2021-10-05 04:12:22 -05:00
|
|
|
"encoding/json"
|
2023-09-26 13:02:11 -05:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2021-10-05 04:12:22 -05:00
|
|
|
"path"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
"github.com/docker/distribution/registry/storage/driver"
|
|
|
|
guuid "github.com/gofrs/uuid"
|
2021-10-05 04:12:22 -05:00
|
|
|
godigest "github.com/opencontainers/go-digest"
|
|
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
|
|
. "github.com/smartystreets/goconvey/convey"
|
2022-10-20 11:39:20 -05:00
|
|
|
|
2024-01-31 23:34:07 -05:00
|
|
|
zerr "zotregistry.dev/zot/errors"
|
|
|
|
"zotregistry.dev/zot/pkg/extensions/monitoring"
|
|
|
|
"zotregistry.dev/zot/pkg/log"
|
|
|
|
"zotregistry.dev/zot/pkg/storage"
|
|
|
|
"zotregistry.dev/zot/pkg/storage/cache"
|
|
|
|
common "zotregistry.dev/zot/pkg/storage/common"
|
|
|
|
"zotregistry.dev/zot/pkg/storage/local"
|
|
|
|
"zotregistry.dev/zot/pkg/storage/s3"
|
|
|
|
storageTypes "zotregistry.dev/zot/pkg/storage/types"
|
|
|
|
. "zotregistry.dev/zot/pkg/test/image-utils"
|
|
|
|
"zotregistry.dev/zot/pkg/test/mocks"
|
|
|
|
tskip "zotregistry.dev/zot/pkg/test/skip"
|
2021-10-05 04:12:22 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
repoName = "test"
|
2022-12-10 19:38:01 -05:00
|
|
|
tag = "1.0"
|
2021-10-05 04:12:22 -05:00
|
|
|
)
|
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
var errUnexpectedError = errors.New("unexpected err")
|
|
|
|
|
|
|
|
func TestLocalCheckAllBlobsIntegrity(t *testing.T) {
|
|
|
|
Convey("test with local storage", t, func() {
|
|
|
|
tdir := t.TempDir()
|
|
|
|
log := log.NewLogger("debug", "")
|
|
|
|
metrics := monitoring.NewMetricsServer(false, log)
|
|
|
|
cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
|
|
|
|
RootDir: tdir,
|
|
|
|
Name: "cache",
|
|
|
|
UseRelPaths: true,
|
|
|
|
}, log)
|
|
|
|
driver := local.New(true)
|
|
|
|
imgStore := local.NewImageStore(tdir, true, true, log, metrics, nil, cacheDriver)
|
|
|
|
|
|
|
|
RunCheckAllBlobsIntegrityTests(t, imgStore, driver, log)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestS3CheckAllBlobsIntegrity(t *testing.T) {
|
2023-10-05 06:34:50 -05:00
|
|
|
tskip.SkipS3(t)
|
2023-09-26 13:02:11 -05:00
|
|
|
|
|
|
|
Convey("test with S3 storage", t, func() {
|
|
|
|
uuid, err := guuid.NewV4()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2021-10-05 04:12:22 -05:00
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
testDir := path.Join("/oci-repo-test", uuid.String())
|
|
|
|
tdir := t.TempDir()
|
|
|
|
log := log.NewLogger("debug", "")
|
2021-10-05 04:12:22 -05:00
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
var store driver.StorageDriver
|
|
|
|
store, imgStore, _ := createObjectsStore(testDir, tdir)
|
|
|
|
defer cleanupStorage(store, testDir)
|
2021-10-05 04:12:22 -05:00
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
driver := s3.New(store)
|
|
|
|
|
|
|
|
RunCheckAllBlobsIntegrityTests(t, imgStore, driver, log)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func RunCheckAllBlobsIntegrityTests( //nolint: thelper
|
|
|
|
t *testing.T, imgStore storageTypes.ImageStore, driver storageTypes.Driver, log log.Logger,
|
|
|
|
) {
|
|
|
|
Convey("Scrub only one repo", func() {
|
2021-10-05 04:12:22 -05:00
|
|
|
// initialize repo
|
2022-03-07 03:55:12 -05:00
|
|
|
err := imgStore.InitRepo(repoName)
|
2021-10-05 04:12:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
2021-12-13 14:23:31 -05:00
|
|
|
ok := imgStore.DirExists(path.Join(imgStore.RootDir(), repoName))
|
2021-10-05 04:12:22 -05:00
|
|
|
So(ok, ShouldBeTrue)
|
2021-12-13 14:23:31 -05:00
|
|
|
storeCtlr := storage.StoreController{}
|
|
|
|
storeCtlr.DefaultStore = imgStore
|
2023-09-26 13:02:11 -05:00
|
|
|
So(storeCtlr.GetImageStore(repoName), ShouldResemble, imgStore)
|
2021-10-05 04:12:22 -05:00
|
|
|
|
2024-01-17 13:20:07 -05:00
|
|
|
image := CreateRandomImage()
|
2021-10-05 04:12:22 -05:00
|
|
|
|
2024-01-17 13:20:07 -05:00
|
|
|
err = WriteImageToFileSystem(image, repoName, tag, storeCtlr)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
2022-10-22 15:46:13 -05:00
|
|
|
|
2021-10-05 04:12:22 -05:00
|
|
|
Convey("Blobs integrity not affected", func() {
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
2023-09-05 11:48:56 -05:00
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
2021-10-05 04:12:22 -05:00
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2021-10-05 04:12:22 -05:00
|
|
|
So(actual, ShouldContainSubstring, "test 1.0 ok")
|
2024-01-25 14:12:21 -05:00
|
|
|
|
|
|
|
err = WriteMultiArchImageToFileSystem(CreateMultiarchWith().RandomImages(0).Build(), repoName, "2.0", storeCtlr)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff = bytes.NewBufferString("")
|
|
|
|
|
|
|
|
res, err = storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
str = space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual = strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldContainSubstring, "test 1.0 ok")
|
|
|
|
So(actual, ShouldContainSubstring, "test 2.0 ok")
|
2021-10-05 04:12:22 -05:00
|
|
|
})
|
|
|
|
|
2023-11-24 03:40:10 -05:00
|
|
|
Convey("Blobs integrity with context done", func() {
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
cancel()
|
|
|
|
|
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(ctx)
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldNotContainSubstring, "test 1.0 ok")
|
|
|
|
})
|
|
|
|
|
2021-10-05 04:12:22 -05:00
|
|
|
Convey("Manifest integrity affected", func() {
|
|
|
|
// get content of manifest file
|
2024-01-17 13:20:07 -05:00
|
|
|
content, _, _, err := imgStore.GetImageManifest(repoName, image.ManifestDescriptor.Digest.String())
|
2021-10-05 04:12:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// delete content of manifest file
|
2024-01-17 13:20:07 -05:00
|
|
|
manifestDig := image.ManifestDescriptor.Digest.Encoded()
|
2022-12-10 19:38:01 -05:00
|
|
|
manifestFile := path.Join(imgStore.RootDir(), repoName, "/blobs/sha256", manifestDig)
|
2023-09-26 13:02:11 -05:00
|
|
|
err = driver.Delete(manifestFile)
|
2021-10-05 04:12:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
defer func() {
|
|
|
|
// put manifest content back to file
|
|
|
|
_, err = driver.WriteFile(manifestFile, content)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
}()
|
|
|
|
|
2021-10-05 04:12:22 -05:00
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
2023-09-05 11:48:56 -05:00
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
2021-10-05 04:12:22 -05:00
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2024-01-25 14:12:21 -05:00
|
|
|
So(actual, ShouldNotContainSubstring, "affected")
|
2021-10-05 04:12:22 -05:00
|
|
|
|
2023-09-01 12:54:39 -05:00
|
|
|
index, err := common.GetIndex(imgStore, repoName, log)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
So(len(index.Manifests), ShouldEqual, 1)
|
2023-09-26 13:02:11 -05:00
|
|
|
|
|
|
|
_, err = driver.WriteFile(manifestFile, []byte("invalid content"))
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff = bytes.NewBufferString("")
|
2022-12-10 19:38:01 -05:00
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
res, err = storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
res.PrintScrubResults(buff)
|
2021-10-05 04:12:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-09-26 13:02:11 -05:00
|
|
|
|
|
|
|
str = space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual = strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
// verify error message
|
2023-12-08 03:05:02 -05:00
|
|
|
So(actual, ShouldContainSubstring, fmt.Sprintf("test 1.0 affected %s invalid manifest content", manifestDig))
|
2023-09-26 13:02:11 -05:00
|
|
|
|
|
|
|
index, err = common.GetIndex(imgStore, repoName, log)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
So(len(index.Manifests), ShouldEqual, 1)
|
2024-01-25 14:12:21 -05:00
|
|
|
manifestDescriptor := index.Manifests[0]
|
2023-09-26 13:02:11 -05:00
|
|
|
|
2024-01-25 14:12:21 -05:00
|
|
|
_, _, err = storage.CheckManifestAndConfig(repoName, manifestDescriptor, []byte("invalid content"), imgStore)
|
|
|
|
So(err, ShouldNotBeNil)
|
2021-10-05 04:12:22 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Config integrity affected", func() {
|
|
|
|
// get content of config file
|
2024-01-17 13:20:07 -05:00
|
|
|
content, err := imgStore.GetBlobContent(repoName, image.ConfigDescriptor.Digest)
|
2021-10-05 04:12:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// delete content of config file
|
2024-01-17 13:20:07 -05:00
|
|
|
configDig := image.ConfigDescriptor.Digest.Encoded()
|
2022-12-10 19:38:01 -05:00
|
|
|
configFile := path.Join(imgStore.RootDir(), repoName, "/blobs/sha256", configDig)
|
2023-09-26 13:02:11 -05:00
|
|
|
err = driver.Delete(configFile)
|
2021-10-05 04:12:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
defer func() {
|
|
|
|
// put config content back to file
|
|
|
|
_, err = driver.WriteFile(configFile, content)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
}()
|
|
|
|
|
2021-10-05 04:12:22 -05:00
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
2023-09-05 11:48:56 -05:00
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
2021-10-05 04:12:22 -05:00
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2023-12-08 03:05:02 -05:00
|
|
|
So(actual, ShouldContainSubstring, fmt.Sprintf("test 1.0 affected %s blob not found", configDig))
|
2021-10-05 04:12:22 -05:00
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
_, err = driver.WriteFile(configFile, []byte("invalid content"))
|
2021-10-05 04:12:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
2023-09-26 13:02:11 -05:00
|
|
|
|
|
|
|
buff = bytes.NewBufferString("")
|
|
|
|
|
|
|
|
res, err = storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
str = space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual = strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2023-12-08 03:05:02 -05:00
|
|
|
So(actual, ShouldContainSubstring, fmt.Sprintf("test 1.0 affected %s invalid server config", configDig))
|
2021-10-05 04:12:22 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Layers integrity affected", func() {
|
|
|
|
// get content of layer
|
2024-01-17 13:20:07 -05:00
|
|
|
content, err := imgStore.GetBlobContent(repoName, image.Manifest.Layers[0].Digest)
|
2021-10-05 04:12:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// delete content of layer file
|
2024-01-17 13:20:07 -05:00
|
|
|
layerDig := image.Manifest.Layers[0].Digest.Encoded()
|
2022-12-10 19:38:01 -05:00
|
|
|
layerFile := path.Join(imgStore.RootDir(), repoName, "/blobs/sha256", layerDig)
|
2023-09-26 13:02:11 -05:00
|
|
|
_, err = driver.WriteFile(layerFile, []byte(" "))
|
2021-10-05 04:12:22 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
defer func() {
|
|
|
|
// put layer content back to file
|
|
|
|
_, err = driver.WriteFile(layerFile, content)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
}()
|
|
|
|
|
2021-10-05 04:12:22 -05:00
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
2023-09-05 11:48:56 -05:00
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
2021-10-05 04:12:22 -05:00
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2023-12-08 03:05:02 -05:00
|
|
|
So(actual, ShouldContainSubstring, fmt.Sprintf("test 1.0 affected %s bad blob digest", layerDig))
|
2021-10-05 04:12:22 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Layer not found", func() {
|
2023-09-26 13:02:11 -05:00
|
|
|
// get content of layer
|
2024-01-25 14:12:21 -05:00
|
|
|
digest := image.Manifest.Layers[0].Digest
|
|
|
|
content, err := imgStore.GetBlobContent(repoName, digest)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2022-12-10 19:38:01 -05:00
|
|
|
// change layer file permissions
|
2024-01-17 13:20:07 -05:00
|
|
|
layerDig := image.Manifest.Layers[0].Digest.Encoded()
|
2023-09-26 13:02:11 -05:00
|
|
|
repoDir := path.Join(imgStore.RootDir(), repoName)
|
2022-12-10 19:38:01 -05:00
|
|
|
layerFile := path.Join(repoDir, "/blobs/sha256", layerDig)
|
2023-09-26 13:02:11 -05:00
|
|
|
err = driver.Delete(layerFile)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
defer func() {
|
|
|
|
_, err := driver.WriteFile(layerFile, content)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
}()
|
|
|
|
|
2023-09-01 12:54:39 -05:00
|
|
|
index, err := common.GetIndex(imgStore, repoName, log)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
So(len(index.Manifests), ShouldEqual, 1)
|
|
|
|
|
2024-01-25 14:12:21 -05:00
|
|
|
// get content of layer
|
|
|
|
imageRes := storage.CheckLayers(repoName, tag, []ispec.Descriptor{{Digest: digest}}, imgStore)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(imageRes.Status, ShouldEqual, "affected")
|
2023-12-08 03:05:02 -05:00
|
|
|
So(imageRes.Error, ShouldEqual, "blob not found")
|
2021-10-05 04:12:22 -05:00
|
|
|
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
2023-09-05 11:48:56 -05:00
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
2021-10-05 04:12:22 -05:00
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2023-12-08 03:05:02 -05:00
|
|
|
So(actual, ShouldContainSubstring, fmt.Sprintf("test 1.0 affected %s blob not found", layerDig))
|
2021-10-05 04:12:22 -05:00
|
|
|
})
|
2022-12-10 19:38:01 -05:00
|
|
|
|
|
|
|
Convey("Scrub index", func() {
|
2024-01-17 13:20:07 -05:00
|
|
|
newImage := CreateRandomImage()
|
|
|
|
newManifestDigest := newImage.ManifestDescriptor.Digest
|
2022-12-10 19:38:01 -05:00
|
|
|
|
2024-01-17 13:20:07 -05:00
|
|
|
err = WriteImageToFileSystem(newImage, repoName, "2.0", storeCtlr)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
idx, err := common.GetIndex(imgStore, repoName, log)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2024-01-17 13:20:07 -05:00
|
|
|
manifestDescriptor, ok := common.GetManifestDescByReference(idx, image.ManifestDescriptor.Digest.String())
|
2023-09-26 13:02:11 -05:00
|
|
|
So(ok, ShouldBeTrue)
|
|
|
|
|
2022-12-10 19:38:01 -05:00
|
|
|
var index ispec.Index
|
|
|
|
index.SchemaVersion = 2
|
2023-09-26 13:02:11 -05:00
|
|
|
index.Subject = &manifestDescriptor
|
2022-12-10 19:38:01 -05:00
|
|
|
index.Manifests = []ispec.Descriptor{
|
|
|
|
{
|
|
|
|
MediaType: ispec.MediaTypeImageManifest,
|
|
|
|
Digest: newManifestDigest,
|
2024-01-17 13:20:07 -05:00
|
|
|
Size: newImage.ManifestDescriptor.Size,
|
2022-12-10 19:38:01 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
indexBlob, err := json.Marshal(index)
|
|
|
|
So(err, ShouldBeNil)
|
2023-05-12 11:32:01 -05:00
|
|
|
indexDigest, _, err := imgStore.PutImageManifest(repoName, "", ispec.MediaTypeImageIndex, indexBlob)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
2023-09-05 11:48:56 -05:00
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
2022-12-10 19:38:01 -05:00
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2022-12-10 19:38:01 -05:00
|
|
|
So(actual, ShouldContainSubstring, "test 1.0 ok")
|
|
|
|
So(actual, ShouldContainSubstring, "test ok")
|
|
|
|
|
2023-11-24 03:40:10 -05:00
|
|
|
// test scrub context done
|
|
|
|
buff = bytes.NewBufferString("")
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
cancel()
|
|
|
|
|
|
|
|
res, err = storeCtlr.CheckAllBlobsIntegrity(ctx)
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
|
|
|
|
str = space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual = strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldNotContainSubstring, "test 1.0 ok")
|
|
|
|
So(actual, ShouldNotContainSubstring, "test ok")
|
|
|
|
|
2022-12-10 19:38:01 -05:00
|
|
|
// test scrub index - errors
|
2023-09-26 13:02:11 -05:00
|
|
|
manifestFile := path.Join(imgStore.RootDir(), repoName, "/blobs/sha256", newManifestDigest.Encoded())
|
2024-01-25 14:12:21 -05:00
|
|
|
_, err = driver.WriteFile(manifestFile, []byte("invalid content"))
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff = bytes.NewBufferString("")
|
|
|
|
|
|
|
|
res, err = storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
str = space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual = strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldContainSubstring, "test affected")
|
|
|
|
|
|
|
|
// delete content of manifest file
|
2023-09-26 13:02:11 -05:00
|
|
|
err = driver.Delete(manifestFile)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff = bytes.NewBufferString("")
|
|
|
|
|
|
|
|
res, err = storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
str = space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual = strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldContainSubstring, "test affected")
|
|
|
|
|
2022-12-10 19:38:01 -05:00
|
|
|
indexFile := path.Join(imgStore.RootDir(), repoName, "/blobs/sha256", indexDigest.Encoded())
|
2023-09-26 13:02:11 -05:00
|
|
|
err = driver.Delete(indexFile)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff = bytes.NewBufferString("")
|
|
|
|
|
2023-09-05 11:48:56 -05:00
|
|
|
res, err = storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
2022-12-10 19:38:01 -05:00
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
str = space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual = strings.TrimSpace(str)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2024-01-25 14:12:21 -05:00
|
|
|
So(actual, ShouldContainSubstring, "test 1.0 ok")
|
|
|
|
So(actual, ShouldNotContainSubstring, "test affected")
|
2022-12-10 19:38:01 -05:00
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
index.Manifests[0].MediaType = "invalid"
|
|
|
|
indexBlob, err = json.Marshal(index)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
_, err = driver.WriteFile(indexFile, indexBlob)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff = bytes.NewBufferString("")
|
|
|
|
|
2023-09-05 11:48:56 -05:00
|
|
|
res, err = storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
2022-12-10 19:38:01 -05:00
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2024-01-25 14:12:21 -05:00
|
|
|
_, _, err = storage.CheckManifestAndConfig(repoName, index.Manifests[0], []byte{}, imgStore)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
So(err, ShouldEqual, zerr.ErrBadManifest)
|
|
|
|
|
2022-12-10 19:38:01 -05:00
|
|
|
str = space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual = strings.TrimSpace(str)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldContainSubstring, "test affected")
|
|
|
|
|
|
|
|
_, err = driver.WriteFile(indexFile, []byte("invalid cotent"))
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
err := driver.Delete(indexFile)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
}()
|
|
|
|
|
|
|
|
buff = bytes.NewBufferString("")
|
|
|
|
|
|
|
|
res, err = storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
str = space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual = strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2022-12-10 19:38:01 -05:00
|
|
|
So(actual, ShouldContainSubstring, "test affected")
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("Manifest not found", func() {
|
|
|
|
// delete manifest file
|
2024-01-17 13:20:07 -05:00
|
|
|
manifestDig := image.ManifestDescriptor.Digest.Encoded()
|
2022-12-10 19:38:01 -05:00
|
|
|
manifestFile := path.Join(imgStore.RootDir(), repoName, "/blobs/sha256", manifestDig)
|
2023-09-26 13:02:11 -05:00
|
|
|
err = driver.Delete(manifestFile)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
2023-09-05 11:48:56 -05:00
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
2022-12-10 19:38:01 -05:00
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
2023-09-26 13:02:11 -05:00
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
2024-01-25 14:12:21 -05:00
|
|
|
So(actual, ShouldNotContainSubstring, fmt.Sprintf("test 1.0 affected %s blob not found", manifestDig))
|
2022-12-10 19:38:01 -05:00
|
|
|
|
2023-09-01 12:54:39 -05:00
|
|
|
index, err := common.GetIndex(imgStore, repoName, log)
|
2022-12-10 19:38:01 -05:00
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2023-09-26 13:02:11 -05:00
|
|
|
So(len(index.Manifests), ShouldEqual, 1)
|
2022-12-10 19:38:01 -05:00
|
|
|
})
|
2023-09-26 13:02:11 -05:00
|
|
|
|
|
|
|
Convey("use the result of an already scrubed manifest which is the subject of the current manifest", func() {
|
|
|
|
index, err := common.GetIndex(imgStore, repoName, log)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
2024-01-17 13:20:07 -05:00
|
|
|
manifestDescriptor, ok := common.GetManifestDescByReference(index, image.ManifestDescriptor.Digest.String())
|
2023-09-26 13:02:11 -05:00
|
|
|
So(ok, ShouldBeTrue)
|
|
|
|
|
2023-09-27 13:34:48 -05:00
|
|
|
err = WriteImageToFileSystem(CreateDefaultImageWith().Subject(&manifestDescriptor).Build(),
|
2023-09-26 13:02:11 -05:00
|
|
|
repoName, "0.0.1", storeCtlr)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldContainSubstring, "test 1.0 ok")
|
|
|
|
So(actual, ShouldContainSubstring, "test 0.0.1 ok")
|
|
|
|
})
|
2024-01-25 14:12:21 -05:00
|
|
|
|
|
|
|
Convey("the subject of the current manifest doesn't exist", func() {
|
|
|
|
index, err := common.GetIndex(imgStore, repoName, log)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
manifestDescriptor, ok := common.GetManifestDescByReference(index, image.ManifestDescriptor.Digest.String())
|
|
|
|
So(ok, ShouldBeTrue)
|
|
|
|
|
|
|
|
err = WriteImageToFileSystem(CreateDefaultImageWith().Subject(&manifestDescriptor).Build(),
|
|
|
|
repoName, "0.0.2", storeCtlr)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// get content of manifest file
|
|
|
|
content, _, _, err := imgStore.GetImageManifest(repoName, manifestDescriptor.Digest.String())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// delete content of manifest file
|
|
|
|
manifestDig := image.ManifestDescriptor.Digest.Encoded()
|
|
|
|
manifestFile := path.Join(imgStore.RootDir(), repoName, "/blobs/sha256", manifestDig)
|
|
|
|
err = driver.Delete(manifestFile)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
// put manifest content back to file
|
|
|
|
_, err = driver.WriteFile(manifestFile, content)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
}()
|
|
|
|
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldContainSubstring, "test 0.0.2 affected")
|
|
|
|
})
|
|
|
|
|
|
|
|
Convey("the subject of the current index doesn't exist", func() {
|
|
|
|
index, err := common.GetIndex(imgStore, repoName, log)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
manifestDescriptor, ok := common.GetManifestDescByReference(index, image.ManifestDescriptor.Digest.String())
|
|
|
|
So(ok, ShouldBeTrue)
|
|
|
|
|
|
|
|
err = WriteMultiArchImageToFileSystem(CreateMultiarchWith().RandomImages(1).Subject(&manifestDescriptor).Build(),
|
|
|
|
repoName, "0.0.2", storeCtlr)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// get content of manifest file
|
|
|
|
content, _, _, err := imgStore.GetImageManifest(repoName, manifestDescriptor.Digest.String())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
// delete content of manifest file
|
|
|
|
manifestDig := image.ManifestDescriptor.Digest.Encoded()
|
|
|
|
manifestFile := path.Join(imgStore.RootDir(), repoName, "/blobs/sha256", manifestDig)
|
|
|
|
err = driver.Delete(manifestFile)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
// put manifest content back to file
|
|
|
|
_, err = driver.WriteFile(manifestFile, content)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
}()
|
|
|
|
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
|
|
|
|
res, err := storeCtlr.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldContainSubstring, "test 0.0.2 affected")
|
|
|
|
})
|
2023-09-26 13:02:11 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
Convey("test errors", func() {
|
|
|
|
mockedImgStore := mocks.MockedImageStore{
|
|
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
|
|
return []string{repoName}, nil
|
|
|
|
},
|
|
|
|
ValidateRepoFn: func(name string) (bool, error) {
|
|
|
|
return false, nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
storeController := storage.StoreController{}
|
|
|
|
storeController.DefaultStore = mockedImgStore
|
|
|
|
|
|
|
|
_, err := storeController.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
So(err, ShouldEqual, zerr.ErrRepoBadLayout)
|
|
|
|
|
|
|
|
mockedImgStore = mocks.MockedImageStore{
|
|
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
|
|
return []string{repoName}, nil
|
|
|
|
},
|
|
|
|
GetIndexContentFn: func(repo string) ([]byte, error) {
|
|
|
|
return []byte{}, errUnexpectedError
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
storeController.DefaultStore = mockedImgStore
|
|
|
|
|
|
|
|
_, err = storeController.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
So(err, ShouldNotBeNil)
|
|
|
|
So(err, ShouldEqual, errUnexpectedError)
|
2024-01-17 13:20:07 -05:00
|
|
|
|
|
|
|
manifestDigest := godigest.FromString("abcd")
|
|
|
|
|
|
|
|
mockedImgStore = mocks.MockedImageStore{
|
|
|
|
GetRepositoriesFn: func() ([]string, error) {
|
|
|
|
return []string{repoName}, nil
|
|
|
|
},
|
|
|
|
GetIndexContentFn: func(repo string) ([]byte, error) {
|
|
|
|
var index ispec.Index
|
|
|
|
index.SchemaVersion = 2
|
|
|
|
index.Manifests = []ispec.Descriptor{
|
|
|
|
{
|
|
|
|
MediaType: "InvalidMediaType",
|
|
|
|
Digest: manifestDigest,
|
|
|
|
Size: int64(100),
|
|
|
|
Annotations: map[string]string{ispec.AnnotationRefName: "1.0"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
return json.Marshal(index)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
storeController.DefaultStore = mockedImgStore
|
|
|
|
|
|
|
|
res, err := storeController.CheckAllBlobsIntegrity(context.Background())
|
|
|
|
So(err, ShouldBeNil)
|
|
|
|
|
|
|
|
buff := bytes.NewBufferString("")
|
|
|
|
res.PrintScrubResults(buff)
|
|
|
|
|
|
|
|
space := regexp.MustCompile(`\s+`)
|
|
|
|
str := space.ReplaceAllString(buff.String(), " ")
|
|
|
|
actual := strings.TrimSpace(str)
|
|
|
|
So(actual, ShouldContainSubstring, "REPOSITORY TAG STATUS AFFECTED BLOB ERROR")
|
|
|
|
So(actual, ShouldContainSubstring, fmt.Sprintf("%s 1.0 affected %s invalid manifest content",
|
|
|
|
repoName, manifestDigest.Encoded()))
|
2021-10-05 04:12:22 -05:00
|
|
|
})
|
|
|
|
}
|