zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/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.dev/zot/pkg/api"
    17  	"zotregistry.dev/zot/pkg/api/config"
    18  	extconf "zotregistry.dev/zot/pkg/extensions/config"
    19  	"zotregistry.dev/zot/pkg/extensions/monitoring"
    20  	"zotregistry.dev/zot/pkg/extensions/scrub"
    21  	"zotregistry.dev/zot/pkg/log"
    22  	"zotregistry.dev/zot/pkg/storage"
    23  	"zotregistry.dev/zot/pkg/storage/cache"
    24  	"zotregistry.dev/zot/pkg/storage/local"
    25  	test "zotregistry.dev/zot/pkg/test/common"
    26  	. "zotregistry.dev/zot/pkg/test/image-utils"
    27  	ociutils "zotregistry.dev/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  		defer cm.StopServer()
    74  
    75  		found, err := test.ReadLogFileAndSearchString(logFile.Name(), "blobs/manifest ok", 60*time.Second)
    76  		So(found, ShouldBeTrue)
    77  		So(err, ShouldBeNil)
    78  	})
    79  
    80  	Convey("Blobs integrity affected", t, func(c C) {
    81  		port := test.GetFreePort()
    82  
    83  		logFile, err := os.CreateTemp("", "zot-log*.txt")
    84  		So(err, ShouldBeNil)
    85  
    86  		defer os.Remove(logFile.Name()) // clean up
    87  
    88  		conf := config.New()
    89  		conf.HTTP.Port = port
    90  
    91  		dir := t.TempDir()
    92  
    93  		conf.Storage.RootDirectory = dir
    94  		conf.Storage.Dedupe = false
    95  		conf.Storage.GC = false
    96  
    97  		conf.Log.Output = logFile.Name()
    98  		trueValue := true
    99  		scrubConfig := &extconf.ScrubConfig{
   100  			BaseConfig: extconf.BaseConfig{Enable: &trueValue},
   101  			Interval:   2,
   102  		}
   103  		conf.Extensions = &extconf.ExtensionConfig{
   104  			Scrub: scrubConfig,
   105  		}
   106  
   107  		ctlr := api.NewController(conf)
   108  
   109  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log.NewLogger("debug", ""))
   110  		image := CreateDefaultVulnerableImage()
   111  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   112  		So(err, ShouldBeNil)
   113  
   114  		layerDigest := image.Manifest.Layers[0].Digest
   115  
   116  		err = os.Remove(path.Join(dir, repoName, "blobs/sha256", layerDigest.Encoded()))
   117  		if err != nil {
   118  			panic(err)
   119  		}
   120  
   121  		cm := test.NewControllerManager(ctlr)
   122  		cm.StartAndWait(port)
   123  		defer cm.StopServer()
   124  
   125  		found, err := test.ReadLogFileAndSearchString(logFile.Name(), "blobs/manifest affected", 60*time.Second)
   126  		So(found, ShouldBeTrue)
   127  		So(err, ShouldBeNil)
   128  	})
   129  
   130  	Convey("Generator error - not enough permissions to access root directory", t, func(c C) {
   131  		port := test.GetFreePort()
   132  
   133  		logFile, err := os.CreateTemp("", "zot-log*.txt")
   134  		So(err, ShouldBeNil)
   135  
   136  		defer os.Remove(logFile.Name()) // clean up
   137  
   138  		conf := config.New()
   139  		conf.HTTP.Port = port
   140  
   141  		dir := t.TempDir()
   142  
   143  		conf.Storage.RootDirectory = dir
   144  		conf.Storage.Dedupe = false
   145  		conf.Storage.GC = false
   146  
   147  		conf.Log.Output = logFile.Name()
   148  		trueValue := true
   149  		scrubConfig := &extconf.ScrubConfig{
   150  			BaseConfig: extconf.BaseConfig{Enable: &trueValue},
   151  			Interval:   2,
   152  		}
   153  		conf.Extensions = &extconf.ExtensionConfig{
   154  			Scrub: scrubConfig,
   155  		}
   156  
   157  		ctlr := api.NewController(conf)
   158  
   159  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log.NewLogger("debug", ""))
   160  		image := CreateDefaultVulnerableImage()
   161  
   162  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   163  		So(err, ShouldBeNil)
   164  
   165  		So(os.Chmod(path.Join(dir, repoName), 0o000), ShouldBeNil)
   166  
   167  		cm := test.NewControllerManager(ctlr)
   168  		cm.StartAndWait(port)
   169  		defer cm.StopServer()
   170  
   171  		found, err := test.ReadLogFileAndSearchString(logFile.Name(), "failed to execute generator", 60*time.Second)
   172  		So(found, ShouldBeTrue)
   173  		So(err, ShouldBeNil)
   174  
   175  		So(os.Chmod(path.Join(dir, repoName), 0o755), ShouldBeNil)
   176  	})
   177  }
   178  
   179  func TestRunScrubRepo(t *testing.T) {
   180  	Convey("Blobs integrity not affected", t, func(c C) {
   181  		logFile, err := os.CreateTemp("", "zot-log*.txt")
   182  		So(err, ShouldBeNil)
   183  
   184  		defer os.Remove(logFile.Name()) // clean up
   185  
   186  		conf := config.New()
   187  		conf.Extensions = &extconf.ExtensionConfig{}
   188  		conf.Extensions.Lint = &extconf.LintConfig{}
   189  
   190  		dir := t.TempDir()
   191  		log := log.NewLogger("debug", logFile.Name())
   192  		metrics := monitoring.NewMetricsServer(false, log)
   193  		cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
   194  			RootDir:     dir,
   195  			Name:        "cache",
   196  			UseRelPaths: true,
   197  		}, log)
   198  		imgStore := local.NewImageStore(dir, true,
   199  			true, log, metrics, nil, cacheDriver)
   200  
   201  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log)
   202  		image := CreateDefaultVulnerableImage()
   203  
   204  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   205  		So(err, ShouldBeNil)
   206  
   207  		err = scrub.RunScrubRepo(context.Background(), imgStore, repoName, log)
   208  		So(err, ShouldBeNil)
   209  
   210  		data, err := os.ReadFile(logFile.Name())
   211  		So(err, ShouldBeNil)
   212  		So(string(data), ShouldContainSubstring, "blobs/manifest ok")
   213  	})
   214  
   215  	Convey("Blobs integrity affected", t, func(c C) {
   216  		logFile, err := os.CreateTemp("", "zot-log*.txt")
   217  		So(err, ShouldBeNil)
   218  
   219  		defer os.Remove(logFile.Name()) // clean up
   220  
   221  		conf := config.New()
   222  
   223  		conf.Extensions = &extconf.ExtensionConfig{}
   224  		conf.Extensions.Lint = &extconf.LintConfig{}
   225  
   226  		dir := t.TempDir()
   227  		log := log.NewLogger("debug", logFile.Name())
   228  		metrics := monitoring.NewMetricsServer(false, log)
   229  		cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
   230  			RootDir:     dir,
   231  			Name:        "cache",
   232  			UseRelPaths: true,
   233  		}, log)
   234  		imgStore := local.NewImageStore(dir, true,
   235  			true, log, metrics, nil, cacheDriver)
   236  
   237  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log)
   238  		image := CreateDefaultVulnerableImage()
   239  
   240  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   241  		So(err, ShouldBeNil)
   242  
   243  		layerDigest := image.Manifest.Layers[0].Digest
   244  
   245  		err = os.Remove(path.Join(dir, repoName, "blobs/sha256", layerDigest.Encoded()))
   246  		if err != nil {
   247  			panic(err)
   248  		}
   249  
   250  		err = scrub.RunScrubRepo(context.Background(), imgStore, repoName, log)
   251  		So(err, ShouldBeNil)
   252  
   253  		data, err := os.ReadFile(logFile.Name())
   254  		So(err, ShouldBeNil)
   255  		So(string(data), ShouldContainSubstring, "blobs/manifest affected")
   256  	})
   257  
   258  	Convey("CheckRepo error - not enough permissions to access root directory", t, func(c C) {
   259  		logFile, err := os.CreateTemp("", "zot-log*.txt")
   260  		So(err, ShouldBeNil)
   261  
   262  		defer os.Remove(logFile.Name()) // clean up
   263  
   264  		conf := config.New()
   265  		conf.Extensions = &extconf.ExtensionConfig{}
   266  		conf.Extensions.Lint = &extconf.LintConfig{}
   267  
   268  		dir := t.TempDir()
   269  		log := log.NewLogger("debug", logFile.Name())
   270  		metrics := monitoring.NewMetricsServer(false, log)
   271  		cacheDriver, _ := storage.Create("boltdb", cache.BoltDBDriverParameters{
   272  			RootDir:     dir,
   273  			Name:        "cache",
   274  			UseRelPaths: true,
   275  		}, log)
   276  		imgStore := local.NewImageStore(dir, true, true, log, metrics, nil, cacheDriver)
   277  
   278  		srcStorageCtlr := ociutils.GetDefaultStoreController(dir, log)
   279  		image := CreateDefaultVulnerableImage()
   280  
   281  		err = WriteImageToFileSystem(image, repoName, "0.0.1", srcStorageCtlr)
   282  		So(err, ShouldBeNil)
   283  
   284  		So(os.Chmod(path.Join(dir, repoName), 0o000), ShouldBeNil)
   285  
   286  		err = scrub.RunScrubRepo(context.Background(), imgStore, repoName, log)
   287  		So(err, ShouldNotBeNil)
   288  
   289  		data, err := os.ReadFile(logFile.Name())
   290  		So(err, ShouldBeNil)
   291  		So(string(data), ShouldContainSubstring,
   292  			fmt.Sprintf("failed to run scrub for %s", imgStore.RootDir()))
   293  		So(os.Chmod(path.Join(dir, repoName), 0o755), ShouldBeNil)
   294  	})
   295  }