diff --git a/pkg/api/config/config.go b/pkg/api/config/config.go index 76ada3f0..79b5ad87 100644 --- a/pkg/api/config/config.go +++ b/pkg/api/config/config.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "os" "time" "github.com/getlantern/deepcopy" @@ -144,6 +145,27 @@ func New() *Config { } } +func (expConfig StorageConfig) ParamsEqual(actConfig StorageConfig) bool { + return expConfig.GC == actConfig.GC && expConfig.Dedupe == actConfig.Dedupe && + expConfig.GCDelay == actConfig.GCDelay && expConfig.GCInterval == actConfig.GCInterval +} + +// SameFile compare two files. +// This method will first do the stat of two file and compare using os.SameFile method. +func SameFile(str1, str2 string) (bool, error) { + sFile, err := os.Stat(str1) + if err != nil { + return false, err + } + + tFile, err := os.Stat(str2) + if err != nil { + return false, err + } + + return os.SameFile(sFile, tFile), nil +} + // Sanitize makes a sanitized copy of the config removing any secrets. func (c *Config) Sanitize() *Config { sanitizedConfig := &Config{} diff --git a/pkg/api/config/config_elevated_test.go b/pkg/api/config/config_elevated_test.go new file mode 100644 index 00000000..3b1a0b0c --- /dev/null +++ b/pkg/api/config/config_elevated_test.go @@ -0,0 +1,32 @@ +//go:build needprivileges +// +build needprivileges + +package config_test + +import ( + "syscall" + "testing" + + . "github.com/smartystreets/goconvey/convey" + + "zotregistry.io/zot/pkg/api/config" +) + +func TestMountConfig(t *testing.T) { + Convey("Test config utils mounting same directory", t, func() { + // If two dirs are mounting to same location SameFile should be same + dir1 := t.TempDir() + dir2 := t.TempDir() + dir3 := t.TempDir() + + err := syscall.Mount(dir3, dir1, "", syscall.MS_BIND, "") + So(err, ShouldBeNil) + + err = syscall.Mount(dir3, dir2, "", syscall.MS_BIND, "") + So(err, ShouldBeNil) + + isSame, err := config.SameFile(dir1, dir2) + So(err, ShouldBeNil) + So(isSame, ShouldBeTrue) + }) +} diff --git a/pkg/api/config/config_test.go b/pkg/api/config/config_test.go new file mode 100644 index 00000000..85611e0d --- /dev/null +++ b/pkg/api/config/config_test.go @@ -0,0 +1,67 @@ +package config_test + +import ( + "testing" + "time" + + . "github.com/smartystreets/goconvey/convey" + "zotregistry.io/zot/pkg/api/config" +) + +func TestConfig(t *testing.T) { + Convey("Test config utils", t, func() { + firstStorageConfig := config.StorageConfig{ + GC: true, Dedupe: true, + GCDelay: 1 * time.Minute, GCInterval: 1 * time.Hour, + } + secondStorageConfig := config.StorageConfig{ + GC: true, Dedupe: true, + GCDelay: 1 * time.Minute, GCInterval: 1 * time.Hour, + } + + So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeTrue) + + firstStorageConfig.GC = false + + So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeFalse) + + firstStorageConfig.GC = true + firstStorageConfig.Dedupe = false + + So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeFalse) + + firstStorageConfig.Dedupe = true + firstStorageConfig.GCDelay = 2 * time.Minute + + So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeFalse) + + firstStorageConfig.GCDelay = 1 * time.Minute + firstStorageConfig.GCInterval = 2 * time.Hour + + So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeFalse) + + firstStorageConfig.GCInterval = 1 * time.Hour + + So(firstStorageConfig.ParamsEqual(secondStorageConfig), ShouldBeTrue) + + isSame, err := config.SameFile("test-config", "test") + So(err, ShouldNotBeNil) + So(isSame, ShouldBeFalse) + + dir1 := t.TempDir() + + isSame, err = config.SameFile(dir1, "test") + So(err, ShouldNotBeNil) + So(isSame, ShouldBeFalse) + + dir2 := t.TempDir() + + isSame, err = config.SameFile(dir1, dir2) + So(err, ShouldBeNil) + So(isSame, ShouldBeFalse) + + isSame, err = config.SameFile(dir1, dir1) + So(err, ShouldBeNil) + So(isSame, ShouldBeTrue) + }) +} diff --git a/pkg/api/controller.go b/pkg/api/controller.go index b9f747bd..bf2eff32 100644 --- a/pkg/api/controller.go +++ b/pkg/api/controller.go @@ -21,6 +21,7 @@ import ( "zotregistry.io/zot/pkg/api/config" ext "zotregistry.io/zot/pkg/extensions" extconf "zotregistry.io/zot/pkg/extensions/config" + "zotregistry.io/zot/pkg/extensions/lint" "zotregistry.io/zot/pkg/extensions/monitoring" "zotregistry.io/zot/pkg/log" "zotregistry.io/zot/pkg/storage" @@ -281,54 +282,11 @@ func (c *Controller) InitImageStore(reloadCtx context.Context) error { if len(c.Config.Storage.SubPaths) > 0 { subPaths := c.Config.Storage.SubPaths - subImageStore := make(map[string]storage.ImageStore) + subImageStore, err := c.getSubStore(subPaths, linter) + if err != nil { + c.Log.Error().Err(err).Msg("controller: error getting sub image store") - // creating image store per subpaths - for route, storageConfig := range subPaths { - // no need to validate hard links work on s3 - if storageConfig.Dedupe && storageConfig.StorageDriver == nil { - err := storage.ValidateHardLink(storageConfig.RootDirectory) - if err != nil { - c.Log.Warn().Msg("input storage root directory filesystem does not supports hardlinking, " + - "disabling dedupe functionality") - - storageConfig.Dedupe = false - } - } - - if storageConfig.StorageDriver == nil { - // false positive lint - linter does not implement Lint method - // nolint: typecheck - subImageStore[route] = storage.NewImageStore(storageConfig.RootDirectory, - storageConfig.GC, storageConfig.GCDelay, storageConfig.Dedupe, storageConfig.Commit, c.Log, c.Metrics, linter) - } else { - storeName := fmt.Sprintf("%v", storageConfig.StorageDriver["name"]) - if storeName != storage.S3StorageDriverName { - c.Log.Fatal().Err(errors.ErrBadConfig).Msgf("unsupported storage driver: %s", storageConfig.StorageDriver["name"]) - } - - // Init a Storager from connection string. - store, err := factory.Create(storeName, storageConfig.StorageDriver) - if err != nil { - c.Log.Error().Err(err).Str("rootDir", storageConfig.RootDirectory).Msg("Unable to create s3 service") - - return err - } - - /* in the case of s3 c.Config.Storage.RootDirectory is used for caching blobs locally and - c.Config.Storage.StorageDriver["rootdirectory"] is the actual rootDir in s3 */ - rootDir := "/" - if c.Config.Storage.StorageDriver["rootdirectory"] != nil { - rootDir = fmt.Sprintf("%v", c.Config.Storage.StorageDriver["rootdirectory"]) - } - - // false positive lint - linter does not implement Lint method - // nolint: typecheck - subImageStore[route] = s3.NewImageStore(rootDir, storageConfig.RootDirectory, - storageConfig.GC, storageConfig.GCDelay, - storageConfig.Dedupe, storageConfig.Commit, c.Log, c.Metrics, linter, store, - ) - } + return err } c.StoreController.SubStore = subImageStore @@ -340,6 +298,100 @@ func (c *Controller) InitImageStore(reloadCtx context.Context) error { return nil } +func (c *Controller) getSubStore(subPaths map[string]config.StorageConfig, + linter *lint.Linter, +) (map[string]storage.ImageStore, error) { + imgStoreMap := make(map[string]storage.ImageStore, 0) + + subImageStore := make(map[string]storage.ImageStore) + + // creating image store per subpaths + for route, storageConfig := range subPaths { + // no need to validate hard links work on s3 + if storageConfig.Dedupe && storageConfig.StorageDriver == nil { + err := storage.ValidateHardLink(storageConfig.RootDirectory) + if err != nil { + c.Log.Warn().Msg("input storage root directory filesystem does not supports hardlinking, " + + "disabling dedupe functionality") + + storageConfig.Dedupe = false + } + } + + if storageConfig.StorageDriver == nil { + // Compare if subpath root dir is same as default root dir + isSame, _ := config.SameFile(c.Config.Storage.RootDirectory, storageConfig.RootDirectory) + + if isSame { + c.Log.Error().Err(errors.ErrBadConfig).Msg("sub path storage directory is same as root directory") + + return nil, errors.ErrBadConfig + } + + isUnique := true + + // Compare subpath unique files + for file := range imgStoreMap { + // We already have image storage for this file + if compareImageStore(file, storageConfig.RootDirectory) { + subImageStore[route] = imgStoreMap[file] + + isUnique = true + } + } + + // subpath root directory is unique + // add it to uniqueSubFiles + // Create a new image store and assign it to imgStoreMap + if isUnique { + imgStoreMap[storageConfig.RootDirectory] = storage.NewImageStore(storageConfig.RootDirectory, + storageConfig.GC, storageConfig.GCDelay, storageConfig.Dedupe, storageConfig.Commit, c.Log, c.Metrics, linter) + + subImageStore[route] = imgStoreMap[storageConfig.RootDirectory] + } + } else { + storeName := fmt.Sprintf("%v", storageConfig.StorageDriver["name"]) + if storeName != storage.S3StorageDriverName { + c.Log.Fatal().Err(errors.ErrBadConfig).Msgf("unsupported storage driver: %s", storageConfig.StorageDriver["name"]) + } + + // Init a Storager from connection string. + store, err := factory.Create(storeName, storageConfig.StorageDriver) + if err != nil { + c.Log.Error().Err(err).Str("rootDir", storageConfig.RootDirectory).Msg("Unable to create s3 service") + + return nil, err + } + + /* in the case of s3 c.Config.Storage.RootDirectory is used for caching blobs locally and + c.Config.Storage.StorageDriver["rootdirectory"] is the actual rootDir in s3 */ + rootDir := "/" + if c.Config.Storage.StorageDriver["rootdirectory"] != nil { + rootDir = fmt.Sprintf("%v", c.Config.Storage.StorageDriver["rootdirectory"]) + } + + // false positive lint - linter does not implement Lint method + // nolint: typecheck + subImageStore[route] = s3.NewImageStore(rootDir, storageConfig.RootDirectory, + storageConfig.GC, storageConfig.GCDelay, + storageConfig.Dedupe, storageConfig.Commit, c.Log, c.Metrics, linter, store, + ) + } + } + + return subImageStore, nil +} + +func compareImageStore(root1, root2 string) bool { + isSameFile, err := config.SameFile(root1, root2) + // This error is path error that means either of root directory doesn't exist, in that case do string match + if err != nil { + return strings.EqualFold(root1, root2) + } + + return isSameFile +} + func (c *Controller) LoadNewConfig(reloadCtx context.Context, config *config.Config) { // reload access control config c.Config.AccessControl = config.AccessControl diff --git a/pkg/api/controller_test.go b/pkg/api/controller_test.go index 91e3d799..9e634a29 100644 --- a/pkg/api/controller_test.go +++ b/pkg/api/controller_test.go @@ -839,6 +839,70 @@ func TestMultipleInstance(t *testing.T) { So(resp, ShouldNotBeNil) So(resp.StatusCode(), ShouldEqual, http.StatusOK) }) + + Convey("Test zot multiple subpath with same root directory", t, func() { + port := test.GetFreePort() + baseURL := test.GetBaseURL(port) + conf := config.New() + conf.HTTP.Port = port + htpasswdPath := test.MakeHtpasswdFile() + defer os.Remove(htpasswdPath) + + conf.HTTP.Auth = &config.AuthConfig{ + HTPasswd: config.AuthHTPasswd{ + Path: htpasswdPath, + }, + } + ctlr := api.NewController(conf) + globalDir := t.TempDir() + subDir := t.TempDir() + + ctlr.Config.Storage.RootDirectory = globalDir + subPathMap := make(map[string]config.StorageConfig) + subPathMap["/a"] = config.StorageConfig{RootDirectory: globalDir, Dedupe: true, GC: true} + subPathMap["/b"] = config.StorageConfig{RootDirectory: subDir, Dedupe: true, GC: true} + + ctlr.Config.Storage.SubPaths = subPathMap + + err := ctlr.Run(context.Background()) + So(err, ShouldNotBeNil) + + // subpath root directory does not exist. + subPathMap["/a"] = config.StorageConfig{RootDirectory: globalDir, Dedupe: true, GC: true} + subPathMap["/b"] = config.StorageConfig{RootDirectory: subDir, Dedupe: false, GC: true} + + ctlr.Config.Storage.SubPaths = subPathMap + + err = ctlr.Run(context.Background()) + So(err, ShouldNotBeNil) + + subPathMap["/a"] = config.StorageConfig{RootDirectory: subDir, Dedupe: true, GC: true} + subPathMap["/b"] = config.StorageConfig{RootDirectory: subDir, Dedupe: true, GC: true} + + ctlr.Config.Storage.SubPaths = subPathMap + + go startServer(ctlr) + defer stopServer(ctlr) + test.WaitTillServerReady(baseURL) + + // without creds, should get access error + resp, err := resty.R().Get(baseURL + "/v2/") + So(err, ShouldBeNil) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized) + var e api.Error + err = json.Unmarshal(resp.Body(), &e) + So(err, ShouldBeNil) + + // with creds, should get expected status code + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL) + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusNotFound) + + resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/") + So(resp, ShouldNotBeNil) + So(resp.StatusCode(), ShouldEqual, http.StatusOK) + }) } func TestTLSWithBasicAuth(t *testing.T) { diff --git a/pkg/cli/root.go b/pkg/cli/root.go index 7b0891f0..19f8948c 100644 --- a/pkg/cli/root.go +++ b/pkg/cli/root.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "net/http" + "strings" "time" glob "github.com/bmatcuk/doublestar/v4" @@ -202,6 +203,34 @@ func NewCliRootCmd() *cobra.Command { return rootCmd } +func validateStorageConfig(cfg *config.Config) error { + expConfigMap := make(map[string]config.StorageConfig, 0) + + defaultRootDir := cfg.Storage.RootDirectory + + for _, storageConfig := range cfg.Storage.SubPaths { + if strings.EqualFold(defaultRootDir, storageConfig.RootDirectory) { + log.Error().Err(errors.ErrBadConfig).Msg("storage subpaths cannot use default storage root directory") + + return errors.ErrBadConfig + } + + expConfig, ok := expConfigMap[storageConfig.RootDirectory] + if ok { + equal := expConfig.ParamsEqual(storageConfig) + if !equal { + log.Error().Err(errors.ErrBadConfig).Msg("storage config with same root directory should have same parameters") + + return errors.ErrBadConfig + } + } else { + expConfigMap[storageConfig.RootDirectory] = storageConfig + } + } + + return nil +} + func validateConfiguration(config *config.Config) error { if err := validateGC(config); err != nil { return err @@ -215,6 +244,10 @@ func validateConfiguration(config *config.Config) error { return err } + if err := validateStorageConfig(config); err != nil { + return err + } + // check authorization config, it should have basic auth enabled or ldap if config.HTTP.RawAccessControl != nil { // checking for anonymous policy only authorization config: no users, no policies but anonymous policy diff --git a/pkg/cli/root_test.go b/pkg/cli/root_test.go index 24e4db6b..5d20b779 100644 --- a/pkg/cli/root_test.go +++ b/pkg/cli/root_test.go @@ -141,6 +141,82 @@ func TestVerify(t *testing.T) { So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic) }) + Convey("Test verify subpath storage config", t, func(c C) { + tmpfile, err := ioutil.TempFile("", "zot-test*.json") + So(err, ShouldBeNil) + defer os.Remove(tmpfile.Name()) // clean up + content := []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/zot-a"},"/b": {"rootDirectory": "/zot-a"}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + os.Args = []string{"cli_test", "verify", tmpfile.Name()} + err = cli.NewServerRootCmd().Execute() + So(err, ShouldBeNil) + + // sub paths that point to same directory should have same storage config. + content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"}, + "/b": {{"rootDirectory": "/zot-a","dedupe":"false"}}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + os.Args = []string{"cli_test", "verify", tmpfile.Name()} + So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic) + + // sub paths that point to default root directory should not be allowed. + content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/tmp/zot","dedupe":"true"},"/b": {{"rootDirectory": "/zot-a"}}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + os.Args = []string{"cli_test", "verify", tmpfile.Name()} + So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic) + + content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true"}, + "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"false"}}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + os.Args = []string{"cli_test", "verify", tmpfile.Name()} + So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic) + + content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true"}, + "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + os.Args = []string{"cli_test", "verify", tmpfile.Name()} + So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic) + + content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"}, + "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + os.Args = []string{"cli_test", "verify", tmpfile.Name()} + So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic) + + content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/tmp/zot","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"}, + "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + os.Args = []string{"cli_test", "verify", tmpfile.Name()} + So(func() { _ = cli.NewServerRootCmd().Execute() }, ShouldPanic) + }) + Convey("Test verify w/ authorization and w/o authentication", t, func(c C) { tmpfile, err := ioutil.TempFile("", "zot-test*.json") So(err, ShouldBeNil) @@ -420,6 +496,51 @@ func TestLoadConfig(t *testing.T) { err := cli.LoadConfiguration(config, "../../examples/config-policy.json") So(err, ShouldBeNil) }) + Convey("Test subpath config combination", t, func(c C) { + config := config.New() + tmpfile, err := ioutil.TempFile("", "zot-test*.json") + So(err, ShouldBeNil) + defer os.Remove(tmpfile.Name()) + content := []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/tmp/zot","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"}, + "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + err = cli.LoadConfiguration(config, tmpfile.Name()) + So(err, ShouldNotBeNil) + + content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"}, + "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + err = cli.LoadConfiguration(config, tmpfile.Name()) + So(err, ShouldNotBeNil) + + content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"}, + "/b": {"rootDirectory": "/zot-a","dedupe":"false"}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + err = cli.LoadConfiguration(config, tmpfile.Name()) + So(err, ShouldNotBeNil) + + content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", + "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"}, + "/b": {"rootDirectory": "/zot-a","dedupe":"true"}}}, + "http":{"address":"127.0.0.1","port":"8080","realm":"zot", + "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) + err = os.WriteFile(tmpfile.Name(), content, 0o0600) + So(err, ShouldBeNil) + err = cli.LoadConfiguration(config, tmpfile.Name()) + So(err, ShouldBeNil) + }) } func TestGC(t *testing.T) { diff --git a/pkg/extensions/sync/sync_test.go b/pkg/extensions/sync/sync_test.go index dfdd3c67..be9dcf28 100644 --- a/pkg/extensions/sync/sync_test.go +++ b/pkg/extensions/sync/sync_test.go @@ -286,8 +286,6 @@ func TestORAS(t *testing.T) { panic(err) } - fmt.Println(fileDir) - srcURL := strings.Join([]string{sctlr.Server.Addr, "/oras-artifact:v2"}, "") cmd = exec.Command("oras", "push", "--plain-http", srcURL, "--config", @@ -1220,7 +1218,9 @@ func TestBasicAuth(t *testing.T) { }, } - destConfig.Storage.RootDirectory = destDir + rootDir := t.TempDir() + + destConfig.Storage.RootDirectory = rootDir regex := ".*" var semver bool