zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/extensions/scrub/scrub_test.go (about)

     1  //go:build scrub
     2  // +build scrub
     3  
     4  package scrub_test
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"os"
    10  	"path"
    11  	"testing"
    12  	"time"
    13  
    14  	. "github.com/smartystreets/goconvey/convey"
    15  
    16  	"zotregistry.io/zot/pkg/api"
    17  	"zotregistry.io/zot/pkg/api/config"
    18  	extconf "zotregistry.io/zot/pkg/extensions/config"
    19  	"zotregistry.io/zot/pkg/extensions/monitoring"
    20  	"zotregistry.io/zot/pkg/extensions/scrub"
    21  	"zotregistry.io/zot/pkg/log"
    22  	"zotregistry.io/zot/pkg/storage"
    23  	"zotregistry.io/zot/pkg/storage/cache"
    24  	"zotregistry.io/zot/pkg/storage/local"
    25  	test "zotregistry.io/zot/pkg/test/common"
    26  	. "zotregistry.io/zot/pkg/test/image-utils"
    27  	ociutils "zotregistry.io/zot/pkg/test/oci-utils"
    28  )
    29  
    30  const (
    31  	repoName = "test"
    32  )
    33  
    34  func TestScrubExtension(t *testing.T) {
    35  	Convey("Blobs integrity not affected", t, func(c C) {
    36  		port := test.GetFreePort()
    37  
    38  		logFile, err := os.CreateTemp("", "zot-log*.txt")
    39  		So(err, ShouldBeNil)
    40  
    41  		defer os.Remove(logFile.Name()) // clean up
    42  
    43  		conf := config.New()
    44  		conf.HTTP.Port = port
    45  
    46  		dir := t.TempDir()
    47  		subdir := t.TempDir()
    48  
    49  		conf.Storage.RootDirectory = dir
    50  		conf.Storage.Dedupe = false
    51  		conf.Storage.GC = false
    52  
    53  		substore := config.StorageConfig{RootDirectory: subdir}
    54  		conf.Storage.SubPaths = map[string]config.StorageConfig{"/a": substore}
    55  		conf.Log.Output = logFile.Name()
    56  		trueValue := true
    57  		scrubConfig := &extconf.ScrubConfig{
    58  			BaseConfig: extconf.BaseConfig{Enable: &trueValue},
    59  			Interval:   2,
    60  		}
    61  		conf.Extensions = &extconf.ExtensionConfig{
    62  			Scrub: scrubConfig,
    63  		}
    64  
    65  		ctlr := api.NewController(conf)
    66  
    67  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log.NewLogger("debug", ""))
    68  		err = WriteImageToFileSystem(CreateDefaultVulnerableImage(), repoName, "0.0.1", srcStorageCtlr)
    69  		So(err, ShouldBeNil)
    70  
    71  		cm := test.NewControllerManager(ctlr)
    72  		cm.StartAndWait(port)
    73  		time.Sleep(6 * time.Second)
    74  
    75  		defer cm.StopServer()
    76  
    77  		data, err := os.ReadFile(logFile.Name())
    78  		So(err, ShouldBeNil)
    79  		So(string(data), ShouldContainSubstring, "scrub: blobs/manifest ok")
    80  	})
    81  
    82  	Convey("Blobs integrity affected", t, func(c C) {
    83  		port := test.GetFreePort()
    84  
    85  		logFile, err := os.CreateTemp("", "zot-log*.txt")
    86  		So(err, ShouldBeNil)
    87  
    88  		defer os.Remove(logFile.Name()) // clean up
    89  
    90  		conf := config.New()
    91  		conf.HTTP.Port = port
    92  
    93  		dir := t.TempDir()
    94  
    95  		conf.Storage.RootDirectory = dir
    96  		conf.Storage.Dedupe = false
    97  		conf.Storage.GC = false
    98  
    99  		conf.Log.Output = logFile.Name()
   100  		trueValue := true
   101  		scrubConfig := &extconf.ScrubConfig{
   102  			BaseConfig: extconf.BaseConfig{Enable: &trueValue},
   103  			Interval:   2,
   104  		}
   105  		conf.Extensions = &extconf.ExtensionConfig{
   106  			Scrub: scrubConfig,
   107  		}
   108  
   109  		ctlr := api.NewController(conf)
   110  
   111  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log.NewLogger("debug", ""))
   112  		image := CreateDefaultVulnerableImage()
   113  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   114  		So(err, ShouldBeNil)
   115  
   116  		manifestDigest := image.ManifestDescriptor.Digest
   117  
   118  		err = os.Remove(path.Join(dir, repoName, "blobs/sha256", manifestDigest.Encoded()))
   119  		if err != nil {
   120  			panic(err)
   121  		}
   122  
   123  		cm := test.NewControllerManager(ctlr)
   124  		cm.StartAndWait(port)
   125  		time.Sleep(6 * time.Second)
   126  
   127  		defer cm.StopServer()
   128  
   129  		data, err := os.ReadFile(logFile.Name())
   130  		So(err, ShouldBeNil)
   131  		So(string(data), ShouldContainSubstring, "scrub: blobs/manifest affected")
   132  	})
   133  
   134  	Convey("Generator error - not enough permissions to access root directory", t, func(c C) {
   135  		port := test.GetFreePort()
   136  
   137  		logFile, err := os.CreateTemp("", "zot-log*.txt")
   138  		So(err, ShouldBeNil)
   139  
   140  		defer os.Remove(logFile.Name()) // clean up
   141  
   142  		conf := config.New()
   143  		conf.HTTP.Port = port
   144  
   145  		dir := t.TempDir()
   146  
   147  		conf.Storage.RootDirectory = dir
   148  		conf.Storage.Dedupe = false
   149  		conf.Storage.GC = false
   150  
   151  		conf.Log.Output = logFile.Name()
   152  		trueValue := true
   153  		scrubConfig := &extconf.ScrubConfig{
   154  			BaseConfig: extconf.BaseConfig{Enable: &trueValue},
   155  			Interval:   2,
   156  		}
   157  		conf.Extensions = &extconf.ExtensionConfig{
   158  			Scrub: scrubConfig,
   159  		}
   160  
   161  		ctlr := api.NewController(conf)
   162  
   163  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log.NewLogger("debug", ""))
   164  		image := CreateDefaultVulnerableImage()
   165  
   166  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   167  		So(err, ShouldBeNil)
   168  
   169  		So(os.Chmod(path.Join(dir, repoName), 0o000), ShouldBeNil)
   170  
   171  		cm := test.NewControllerManager(ctlr)
   172  		cm.StartAndWait(port)
   173  		time.Sleep(6 * time.Second)
   174  
   175  		defer cm.StopServer()
   176  
   177  		data, err := os.ReadFile(logFile.Name())
   178  		So(err, ShouldBeNil)
   179  		So(string(data), ShouldContainSubstring, "error while executing generator")
   180  
   181  		So(os.Chmod(path.Join(dir, repoName), 0o755), ShouldBeNil)
   182  	})
   183  }
   184  
   185  func TestRunScrubRepo(t *testing.T) {
   186  	Convey("Blobs integrity not affected", t, func(c C) {
   187  		logFile, err := os.CreateTemp("", "zot-log*.txt")
   188  		So(err, ShouldBeNil)
   189  
   190  		defer os.Remove(logFile.Name()) // clean up
   191  
   192  		conf := config.New()
   193  		conf.Extensions = &extconf.ExtensionConfig{}
   194  		conf.Extensions.Lint = &extconf.LintConfig{}
   195  
   196  		dir := t.TempDir()
   197  		log := log.NewLogger("debug", logFile.Name())
   198  		metrics := monitoring.NewMetricsServer(false, log)
   199  		cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
   200  			RootDir:     dir,
   201  			Name:        "cache",
   202  			UseRelPaths: true,
   203  		}, log)
   204  		imgStore := local.NewImageStore(dir, true,
   205  			true, log, metrics, nil, cacheDriver)
   206  
   207  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log)
   208  		image := CreateDefaultVulnerableImage()
   209  
   210  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   211  		So(err, ShouldBeNil)
   212  
   213  		err = scrub.RunScrubRepo(context.Background(), imgStore, repoName, log)
   214  		So(err, ShouldBeNil)
   215  
   216  		data, err := os.ReadFile(logFile.Name())
   217  		So(err, ShouldBeNil)
   218  		So(string(data), ShouldContainSubstring, "scrub: blobs/manifest ok")
   219  	})
   220  
   221  	Convey("Blobs integrity affected", t, func(c C) {
   222  		logFile, err := os.CreateTemp("", "zot-log*.txt")
   223  		So(err, ShouldBeNil)
   224  
   225  		defer os.Remove(logFile.Name()) // clean up
   226  
   227  		conf := config.New()
   228  
   229  		conf.Extensions = &extconf.ExtensionConfig{}
   230  		conf.Extensions.Lint = &extconf.LintConfig{}
   231  
   232  		dir := t.TempDir()
   233  		log := log.NewLogger("debug", logFile.Name())
   234  		metrics := monitoring.NewMetricsServer(false, log)
   235  		cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
   236  			RootDir:     dir,
   237  			Name:        "cache",
   238  			UseRelPaths: true,
   239  		}, log)
   240  		imgStore := local.NewImageStore(dir, true,
   241  			true, log, metrics, nil, cacheDriver)
   242  
   243  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log)
   244  		image := CreateDefaultVulnerableImage()
   245  
   246  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   247  		So(err, ShouldBeNil)
   248  
   249  		manifestDigest := image.ManifestDescriptor.Digest
   250  
   251  		err = os.Remove(path.Join(dir, repoName, "blobs/sha256", manifestDigest.Encoded()))
   252  		if err != nil {
   253  			panic(err)
   254  		}
   255  
   256  		err = scrub.RunScrubRepo(context.Background(), imgStore, repoName, log)
   257  		So(err, ShouldBeNil)
   258  
   259  		data, err := os.ReadFile(logFile.Name())
   260  		So(err, ShouldBeNil)
   261  		So(string(data), ShouldContainSubstring, "scrub: blobs/manifest affected")
   262  	})
   263  
   264  	Convey("CheckRepo error - not enough permissions to access root directory", t, func(c C) {
   265  		logFile, err := os.CreateTemp("", "zot-log*.txt")
   266  		So(err, ShouldBeNil)
   267  
   268  		defer os.Remove(logFile.Name()) // clean up
   269  
   270  		conf := config.New()
   271  		conf.Extensions = &extconf.ExtensionConfig{}
   272  		conf.Extensions.Lint = &extconf.LintConfig{}
   273  
   274  		dir := t.TempDir()
   275  		log := log.NewLogger("debug", logFile.Name())
   276  		metrics := monitoring.NewMetricsServer(false, log)
   277  		cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
   278  			RootDir:     dir,
   279  			Name:        "cache",
   280  			UseRelPaths: true,
   281  		}, log)
   282  		imgStore := local.NewImageStore(dir, true, true, log, metrics, nil, cacheDriver)
   283  
   284  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log)
   285  		image := CreateDefaultVulnerableImage()
   286  
   287  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   288  		So(err, ShouldBeNil)
   289  
   290  		So(os.Chmod(path.Join(dir, repoName), 0o000), ShouldBeNil)
   291  
   292  		err = scrub.RunScrubRepo(context.Background(), imgStore, repoName, log)
   293  		So(err, ShouldNotBeNil)
   294  
   295  		data, err := os.ReadFile(logFile.Name())
   296  		So(err, ShouldBeNil)
   297  		So(string(data), ShouldContainSubstring,
   298  			fmt.Sprintf("error while running scrub for %s", imgStore.RootDir()))
   299  		So(os.Chmod(path.Join(dir, repoName), 0o755), ShouldBeNil)
   300  	})
   301  }