diff --git a/pkg/plugins/manager/manager_test.go b/pkg/plugins/manager/manager_test.go index e871e14fdca..0a275cf7518 100644 --- a/pkg/plugins/manager/manager_test.go +++ b/pkg/plugins/manager/manager_test.go @@ -397,6 +397,24 @@ func TestPluginManager_Init(t *testing.T) { assert.False(t, pm.plugins[pluginID].IsCorePlugin) assert.NotNil(t, pm.plugins[("test")]) }) + + t.Run("With back-end plugin that is symlinked to plugins dir", func(t *testing.T) { + origAppURL := setting.AppUrl + t.Cleanup(func() { + setting.AppUrl = origAppURL + }) + setting.AppUrl = defaultAppURL + + pm := createManager(t, func(pm *PluginManager) { + pm.Cfg.PluginsPath = "testdata/symbolic-plugin-dirs" + }) + err := pm.Init() + require.NoError(t, err) + // This plugin should be properly registered, even though it is symlinked to prlugins dir + require.Empty(t, pm.scanningErrors) + const pluginID = "test" + assert.NotNil(t, pm.plugins[pluginID]) + }) } func TestPluginManager_IsBackendOnlyPlugin(t *testing.T) { diff --git a/pkg/plugins/manager/testdata/symbolic-plugin-dirs/plugin b/pkg/plugins/manager/testdata/symbolic-plugin-dirs/plugin new file mode 120000 index 00000000000..03d9657e1f6 --- /dev/null +++ b/pkg/plugins/manager/testdata/symbolic-plugin-dirs/plugin @@ -0,0 +1 @@ +../symbolic-file-links/plugin \ No newline at end of file diff --git a/pkg/util/filepath.go b/pkg/util/filepath.go index edfa5d8de8e..f59a71107f8 100644 --- a/pkg/util/filepath.go +++ b/pkg/util/filepath.go @@ -55,28 +55,35 @@ func walk(path string, info os.FileInfo, resolvedPath string, symlinkPathsFollow } return err } - // We only want to lstat on directories. If this entry is a symbolic link to a file, no need to recurse. - if info.IsDir() { - if resolvedPath != "" && info.Mode()&os.ModeSymlink == os.ModeSymlink { - path2, err := os.Readlink(resolvedPath) - if err != nil { - return err - } - // vout("SymLink Path: %v, links to: %v", resolvedPath, path2) - if symlinkPathsFollowed != nil { - if _, ok := symlinkPathsFollowed[path2]; ok { - errMsg := "potential symLink infinite loop, path: %v, link to: %v" - return fmt.Errorf(errMsg, resolvedPath, path2) - } - symlinkPathsFollowed[path2] = true - } - info2, err := os.Lstat(path2) - if err != nil { - return err - } - return walk(path, info2, path2, symlinkPathsFollowed, walkFn) + + if resolvedPath != "" && info.Mode()&os.ModeSymlink == os.ModeSymlink { + // We only want to lstat on directories. If this entry is a symbolic link to a file, no need to recurse. + statInfo, err := os.Stat(resolvedPath) + if err != nil { + return err + } + if !statInfo.IsDir() { + return nil } + path2, err := filepath.EvalSymlinks(resolvedPath) + if err != nil { + return err + } + // vout("SymLink Path: %v, links to: %v", resolvedPath, path2) + if symlinkPathsFollowed != nil { + if _, ok := symlinkPathsFollowed[path2]; ok { + errMsg := "potential symLink infinite loop, path: %v, link to: %v" + return fmt.Errorf(errMsg, resolvedPath, path2) + } + symlinkPathsFollowed[path2] = true + } + info2, err := os.Lstat(path2) + if err != nil { + return err + } + return walk(path, info2, path2, symlinkPathsFollowed, walkFn) + } else if info.IsDir() { list, err := ioutil.ReadDir(path) if err != nil { return walkFn(resolvedPath, info, err)