|
|
|
@ -3,7 +3,6 @@ package loader |
|
|
|
|
import ( |
|
|
|
|
"context" |
|
|
|
|
"fmt" |
|
|
|
|
"os" |
|
|
|
|
"path/filepath" |
|
|
|
|
"sort" |
|
|
|
|
"testing" |
|
|
|
@ -28,13 +27,18 @@ import ( |
|
|
|
|
"github.com/grafana/grafana/pkg/setting" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var compareOpts = []cmp.Option{cmpopts.IgnoreFields(plugins.Plugin{}, "client", "log"), localFSComparer} |
|
|
|
|
var compareOpts = []cmp.Option{cmpopts.IgnoreFields(plugins.Plugin{}, "client", "log"), fsComparer} |
|
|
|
|
|
|
|
|
|
var localFSComparer = cmp.Comparer(func(fs1 plugins.LocalFS, fs2 plugins.LocalFS) bool { |
|
|
|
|
fs1Files := fs1.Files() |
|
|
|
|
fs2Files := fs2.Files() |
|
|
|
|
var fsComparer = cmp.Comparer(func(fs1 plugins.FS, fs2 plugins.FS) bool { |
|
|
|
|
fs1Files, err := fs1.Files() |
|
|
|
|
if err != nil { |
|
|
|
|
panic(err) |
|
|
|
|
} |
|
|
|
|
fs2Files, err := fs2.Files() |
|
|
|
|
if err != nil { |
|
|
|
|
panic(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
finder.NewLocalFinder() |
|
|
|
|
sort.SliceStable(fs1Files, func(i, j int) bool { |
|
|
|
|
return fs1Files[i] < fs1Files[j] |
|
|
|
|
}) |
|
|
|
@ -108,9 +112,8 @@ func TestLoader_Load(t *testing.T) { |
|
|
|
|
}, |
|
|
|
|
Module: "app/plugins/datasource/cloudwatch/module", |
|
|
|
|
BaseURL: "public/app/plugins/datasource/cloudwatch", |
|
|
|
|
FS: plugins.NewLocalFS( |
|
|
|
|
filesInDir(t, filepath.Join(corePluginDir, "app/plugins/datasource/cloudwatch")), |
|
|
|
|
filepath.Join(corePluginDir, "app/plugins/datasource/cloudwatch")), |
|
|
|
|
|
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(corePluginDir, "app/plugins/datasource/cloudwatch")), |
|
|
|
|
Signature: plugins.SignatureInternal, |
|
|
|
|
Class: plugins.Core, |
|
|
|
|
}, |
|
|
|
@ -147,12 +150,9 @@ func TestLoader_Load(t *testing.T) { |
|
|
|
|
Backend: true, |
|
|
|
|
State: "alpha", |
|
|
|
|
}, |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: plugins.NewLocalFS( |
|
|
|
|
filesInDir(t, filepath.Join(parentDir, "testdata/valid-v2-signature/plugin/")), |
|
|
|
|
filepath.Join(parentDir, "testdata/valid-v2-signature/plugin/"), |
|
|
|
|
), |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/valid-v2-signature/plugin/")), |
|
|
|
|
Signature: "valid", |
|
|
|
|
SignatureType: plugins.GrafanaSignature, |
|
|
|
|
SignatureOrg: "Grafana Labs", |
|
|
|
@ -226,20 +226,10 @@ func TestLoader_Load(t *testing.T) { |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Module: "plugins/test-app/module", |
|
|
|
|
BaseURL: "public/plugins/test-app", |
|
|
|
|
FS: plugins.NewLocalFS( |
|
|
|
|
map[string]struct{}{ |
|
|
|
|
filepath.Join(parentDir, "testdata/includes-symlinks", "/MANIFEST.txt"): {}, |
|
|
|
|
filepath.Join(parentDir, "testdata/includes-symlinks", "dashboards/connections.json"): {}, |
|
|
|
|
filepath.Join(parentDir, "testdata/includes-symlinks", "dashboards/extra/memory.json"): {}, |
|
|
|
|
filepath.Join(parentDir, "testdata/includes-symlinks", "plugin.json"): {}, |
|
|
|
|
filepath.Join(parentDir, "testdata/includes-symlinks", "symlink_to_txt"): {}, |
|
|
|
|
filepath.Join(parentDir, "testdata/includes-symlinks", "text.txt"): {}, |
|
|
|
|
}, |
|
|
|
|
filepath.Join(parentDir, "testdata/includes-symlinks"), |
|
|
|
|
), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Module: "plugins/test-app/module", |
|
|
|
|
BaseURL: "public/plugins/test-app", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/includes-symlinks")), |
|
|
|
|
Signature: "valid", |
|
|
|
|
SignatureType: plugins.GrafanaSignature, |
|
|
|
|
SignatureOrg: "Grafana Labs", |
|
|
|
@ -276,13 +266,10 @@ func TestLoader_Load(t *testing.T) { |
|
|
|
|
Backend: true, |
|
|
|
|
State: plugins.AlphaRelease, |
|
|
|
|
}, |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: plugins.NewLocalFS( |
|
|
|
|
filesInDir(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")), |
|
|
|
|
filepath.Join(parentDir, "testdata/unsigned-datasource/plugin"), |
|
|
|
|
), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")), |
|
|
|
|
Signature: "unsigned", |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
@ -330,13 +317,10 @@ func TestLoader_Load(t *testing.T) { |
|
|
|
|
Backend: true, |
|
|
|
|
State: plugins.AlphaRelease, |
|
|
|
|
}, |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: plugins.NewLocalFS( |
|
|
|
|
filesInDir(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")), |
|
|
|
|
filepath.Join(parentDir, "testdata/unsigned-datasource/plugin"), |
|
|
|
|
), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/unsigned-datasource/plugin")), |
|
|
|
|
Signature: plugins.SignatureUnsigned, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
@ -440,14 +424,11 @@ func TestLoader_Load(t *testing.T) { |
|
|
|
|
Backend: false, |
|
|
|
|
}, |
|
|
|
|
DefaultNavURL: "/plugins/test-app/page/root-page-react", |
|
|
|
|
FS: plugins.NewLocalFS(map[string]struct{}{ |
|
|
|
|
filepath.Join(parentDir, "testdata/test-app-with-includes", "dashboards/memory.json"): {}, |
|
|
|
|
filepath.Join(parentDir, "testdata/test-app-with-includes", "plugin.json"): {}, |
|
|
|
|
}, filepath.Join(parentDir, "testdata/test-app-with-includes")), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Signature: plugins.SignatureUnsigned, |
|
|
|
|
Module: "plugins/test-app/module", |
|
|
|
|
BaseURL: "public/plugins/test-app", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/test-app-with-includes")), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Signature: plugins.SignatureUnsigned, |
|
|
|
|
Module: "plugins/test-app/module", |
|
|
|
|
BaseURL: "public/plugins/test-app", |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
@ -532,9 +513,7 @@ func TestLoader_Load_CustomSource(t *testing.T) { |
|
|
|
|
Plugins: []plugins.Dependency{}, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
FS: plugins.NewLocalFS(map[string]struct{}{ |
|
|
|
|
filepath.Join(parentDir, "testdata/cdn/plugin", "plugin.json"): {}, |
|
|
|
|
}, filepath.Join(parentDir, "testdata/cdn/plugin")), |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/cdn/plugin")), |
|
|
|
|
Class: plugins.Bundled, |
|
|
|
|
Signature: plugins.SignatureValid, |
|
|
|
|
BaseURL: "plugin-cdn/grafana-worldmap-panel/0.3.3/public/plugins/grafana-worldmap-panel", |
|
|
|
@ -670,13 +649,10 @@ func TestLoader_Load_MultiplePlugins(t *testing.T) { |
|
|
|
|
Executable: "test", |
|
|
|
|
State: plugins.AlphaRelease, |
|
|
|
|
}, |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: plugins.NewLocalFS(map[string]struct{}{ |
|
|
|
|
filepath.Join(parentDir, "testdata/valid-v2-pvt-signature/plugin/plugin.json"): {}, |
|
|
|
|
filepath.Join(parentDir, "testdata/valid-v2-pvt-signature/plugin/MANIFEST.txt"): {}, |
|
|
|
|
}, filepath.Join(parentDir, "testdata/valid-v2-pvt-signature/plugin")), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "testdata/valid-v2-pvt-signature/plugin")), |
|
|
|
|
Signature: "valid", |
|
|
|
|
SignatureType: plugins.PrivateSignature, |
|
|
|
|
SignatureOrg: "Will Browne", |
|
|
|
@ -795,10 +771,7 @@ func TestLoader_Load_RBACReady(t *testing.T) { |
|
|
|
|
}, |
|
|
|
|
Backend: false, |
|
|
|
|
}, |
|
|
|
|
FS: plugins.NewLocalFS(map[string]struct{}{ |
|
|
|
|
filepath.Join(pluginDir, "plugin.json"): {}, |
|
|
|
|
filepath.Join(pluginDir, "MANIFEST.txt"): {}, |
|
|
|
|
}, pluginDir), |
|
|
|
|
FS: mustNewStaticFSForTests(t, pluginDir), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Signature: plugins.SignatureValid, |
|
|
|
|
SignatureType: plugins.PrivateSignature, |
|
|
|
@ -885,10 +858,7 @@ func TestLoader_Load_Signature_RootURL(t *testing.T) { |
|
|
|
|
Backend: true, |
|
|
|
|
Executable: "test", |
|
|
|
|
}, |
|
|
|
|
FS: plugins.NewLocalFS(map[string]struct{}{ |
|
|
|
|
filepath.Join(filepath.Join(parentDir, "/testdata/valid-v2-pvt-signature-root-url-uri/plugin"), "plugin.json"): {}, |
|
|
|
|
filepath.Join(filepath.Join(parentDir, "/testdata/valid-v2-pvt-signature-root-url-uri/plugin"), "MANIFEST.txt"): {}, |
|
|
|
|
}, filepath.Join(parentDir, "/testdata/valid-v2-pvt-signature-root-url-uri/plugin")), |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(parentDir, "/testdata/valid-v2-pvt-signature-root-url-uri/plugin")), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Signature: plugins.SignatureValid, |
|
|
|
|
SignatureType: plugins.PrivateSignature, |
|
|
|
@ -972,7 +942,7 @@ func TestLoader_Load_DuplicatePlugins(t *testing.T) { |
|
|
|
|
}, |
|
|
|
|
Backend: false, |
|
|
|
|
}, |
|
|
|
|
FS: plugins.NewLocalFS(filesInDir(t, pluginDir), pluginDir), |
|
|
|
|
FS: mustNewStaticFSForTests(t, pluginDir), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Signature: plugins.SignatureValid, |
|
|
|
|
SignatureType: plugins.GrafanaSignature, |
|
|
|
@ -1062,7 +1032,7 @@ func TestLoader_Load_SkipUninitializedPlugins(t *testing.T) { |
|
|
|
|
}, |
|
|
|
|
Backend: false, |
|
|
|
|
}, |
|
|
|
|
FS: plugins.NewLocalFS(filesInDir(t, pluginDir1), pluginDir1), |
|
|
|
|
FS: mustNewStaticFSForTests(t, pluginDir1), |
|
|
|
|
Class: plugins.External, |
|
|
|
|
Signature: plugins.SignatureValid, |
|
|
|
|
SignatureType: plugins.GrafanaSignature, |
|
|
|
@ -1137,10 +1107,9 @@ func TestLoader_Load_NestedPlugins(t *testing.T) { |
|
|
|
|
}, |
|
|
|
|
Backend: true, |
|
|
|
|
}, |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: plugins.NewLocalFS(filesInDir(t, filepath.Join(rootDir, "testdata/nested-plugins/parent")), |
|
|
|
|
filepath.Join(rootDir, "testdata/nested-plugins/parent")), |
|
|
|
|
Module: "plugins/test-datasource/module", |
|
|
|
|
BaseURL: "public/plugins/test-datasource", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(rootDir, "testdata/nested-plugins/parent")), |
|
|
|
|
Signature: plugins.SignatureValid, |
|
|
|
|
SignatureType: plugins.GrafanaSignature, |
|
|
|
|
SignatureOrg: "Grafana Labs", |
|
|
|
@ -1170,10 +1139,9 @@ func TestLoader_Load_NestedPlugins(t *testing.T) { |
|
|
|
|
Plugins: []plugins.Dependency{}, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
Module: "plugins/test-panel/module", |
|
|
|
|
BaseURL: "public/plugins/test-panel", |
|
|
|
|
FS: plugins.NewLocalFS(filesInDir(t, filepath.Join(rootDir, "testdata/nested-plugins/parent/nested")), |
|
|
|
|
filepath.Join(rootDir, "testdata/nested-plugins/parent/nested")), |
|
|
|
|
Module: "plugins/test-panel/module", |
|
|
|
|
BaseURL: "public/plugins/test-panel", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(rootDir, "testdata/nested-plugins/parent/nested")), |
|
|
|
|
Signature: plugins.SignatureValid, |
|
|
|
|
SignatureType: plugins.GrafanaSignature, |
|
|
|
|
SignatureOrg: "Grafana Labs", |
|
|
|
@ -1310,10 +1278,9 @@ func TestLoader_Load_NestedPlugins(t *testing.T) { |
|
|
|
|
}, |
|
|
|
|
Backend: false, |
|
|
|
|
}, |
|
|
|
|
Module: "plugins/myorgid-simple-app/module", |
|
|
|
|
BaseURL: "public/plugins/myorgid-simple-app", |
|
|
|
|
FS: plugins.NewLocalFS(filesInDir(t, filepath.Join(rootDir, "testdata/app-with-child/dist")), |
|
|
|
|
filepath.Join(rootDir, "testdata/app-with-child/dist")), |
|
|
|
|
Module: "plugins/myorgid-simple-app/module", |
|
|
|
|
BaseURL: "public/plugins/myorgid-simple-app", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(rootDir, "testdata/app-with-child/dist")), |
|
|
|
|
DefaultNavURL: "/plugins/myorgid-simple-app/page/root-page-react", |
|
|
|
|
Signature: plugins.SignatureValid, |
|
|
|
|
SignatureType: plugins.GrafanaSignature, |
|
|
|
@ -1349,10 +1316,9 @@ func TestLoader_Load_NestedPlugins(t *testing.T) { |
|
|
|
|
Plugins: []plugins.Dependency{}, |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
Module: "plugins/myorgid-simple-app/child/module", |
|
|
|
|
BaseURL: "public/plugins/myorgid-simple-app", |
|
|
|
|
FS: plugins.NewLocalFS(filesInDir(t, filepath.Join(rootDir, "testdata/app-with-child/dist/child")), |
|
|
|
|
filepath.Join(rootDir, "testdata/app-with-child/dist/child")), |
|
|
|
|
Module: "plugins/myorgid-simple-app/child/module", |
|
|
|
|
BaseURL: "public/plugins/myorgid-simple-app", |
|
|
|
|
FS: mustNewStaticFSForTests(t, filepath.Join(rootDir, "testdata/app-with-child/dist/child")), |
|
|
|
|
IncludedInAppID: parent.ID, |
|
|
|
|
Signature: plugins.SignatureValid, |
|
|
|
|
SignatureType: plugins.GrafanaSignature, |
|
|
|
@ -1421,7 +1387,7 @@ func Test_setPathsBasedOnApp(t *testing.T) { |
|
|
|
|
func newLoader(cfg *config.Cfg, cbs ...func(loader *Loader)) *Loader { |
|
|
|
|
l := New(cfg, &fakes.FakeLicensingService{}, signature.NewUnsignedAuthorizer(cfg), fakes.NewFakePluginRegistry(), |
|
|
|
|
fakes.NewFakeBackendProcessProvider(), fakes.NewFakeProcessManager(), fakes.NewFakeRoleRegistry(), |
|
|
|
|
assetpath.ProvideService(pluginscdn.ProvideService(cfg)), finder.NewLocalFinder(), |
|
|
|
|
assetpath.ProvideService(pluginscdn.ProvideService(cfg)), finder.NewLocalFinder(cfg), |
|
|
|
|
signature.ProvideService(cfg, keystore.ProvideService(kvstore.NewFakeKVStore()))) |
|
|
|
|
|
|
|
|
|
for _, cb := range cbs { |
|
|
|
@ -1453,39 +1419,8 @@ func verifyState(t *testing.T, ps []*plugins.Plugin, reg *fakes.FakePluginRegist |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func filesInDir(t *testing.T, dir string) map[string]struct{} { |
|
|
|
|
files, err := collectFilesWithin(dir) |
|
|
|
|
if err != nil { |
|
|
|
|
t.Logf("Could not collect plugin file info. Err: %v", err) |
|
|
|
|
return map[string]struct{}{} |
|
|
|
|
} |
|
|
|
|
return files |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func collectFilesWithin(dir string) (map[string]struct{}, error) { |
|
|
|
|
files := map[string]struct{}{} |
|
|
|
|
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// skip directories
|
|
|
|
|
if info.IsDir() { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// verify that file is within plugin directory
|
|
|
|
|
//file, err := filepath.Rel(dir, path)
|
|
|
|
|
//if err != nil {
|
|
|
|
|
// return err
|
|
|
|
|
//}
|
|
|
|
|
//if strings.HasPrefix(file, ".."+string(filepath.Separator)) {
|
|
|
|
|
// return fmt.Errorf("file '%s' not inside of plugin directory", file)
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
files[path] = struct{}{} |
|
|
|
|
return nil |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
return files, err |
|
|
|
|
func mustNewStaticFSForTests(t *testing.T, dir string) plugins.FS { |
|
|
|
|
sfs, err := plugins.NewStaticFS(plugins.NewLocalFS(dir)) |
|
|
|
|
require.NoError(t, err) |
|
|
|
|
return sfs |
|
|
|
|
} |
|
|
|
|