From e540848096e992c867ad91c8acc903e9a9b7fcca Mon Sep 17 00:00:00 2001 From: Lapo Docs Date: Thu, 3 Apr 2025 10:56:14 -0600 Subject: [PATCH] Go SDK: Validate that plugin is not using sdk forks --- pkg/analysis/passes/osvscanner/osvscanner.go | 4 ++ pkg/analysis/passes/sdkusage/sdkusage.go | 16 ++++++ pkg/analysis/passes/sdkusage/sdkusage_test.go | 56 +++++++++++++++++-- .../sdkusage/testdata/replaced-sdk/go.mod | 9 +++ pkg/runner/runner.go | 9 ++- 5 files changed, 87 insertions(+), 7 deletions(-) create mode 100644 pkg/analysis/passes/sdkusage/testdata/replaced-sdk/go.mod diff --git a/pkg/analysis/passes/osvscanner/osvscanner.go b/pkg/analysis/passes/osvscanner/osvscanner.go index 2ad8d706..3e393c19 100644 --- a/pkg/analysis/passes/osvscanner/osvscanner.go +++ b/pkg/analysis/passes/osvscanner/osvscanner.go @@ -73,6 +73,10 @@ var scannerTypes = [...]string{ } func run(pass *analysis.Pass) (interface{}, error) { + if os.Getenv("SKIP_OSV_SCANNER") != "" { + return nil, nil + } + archiveFilesPath, ok := pass.ResultOf[archive.Analyzer].(string) if !ok || archiveFilesPath == "" { return nil, nil diff --git a/pkg/analysis/passes/sdkusage/sdkusage.go b/pkg/analysis/passes/sdkusage/sdkusage.go index 176a5d67..3515bbd9 100644 --- a/pkg/analysis/passes/sdkusage/sdkusage.go +++ b/pkg/analysis/passes/sdkusage/sdkusage.go @@ -18,6 +18,7 @@ var ( goSdkNotUsed = &analysis.Rule{Name: "go-sdk-not-used", Severity: analysis.Error} goModNotFound = &analysis.Rule{Name: "go-mod-not-found", Severity: analysis.Error} goModError = &analysis.Rule{Name: "go-mod-error", Severity: analysis.Error} + goSdkReplaced = &analysis.Rule{Name: "go-sdk-replaced", Severity: analysis.Error} goSdkOlderThanTwoMonths = &analysis.Rule{ Name: "go-sdk-older-than-2-months", Severity: analysis.Warning, @@ -39,6 +40,7 @@ var Analyzer = &analysis.Analyzer{ goSdkNotUsed, goModNotFound, goModError, + goSdkReplaced, goSdkOlderThanTwoMonths, goSdkOlderThanFiveMonths, }, @@ -183,6 +185,20 @@ func run(pass *analysis.Pass) (interface{}, error) { return nil, nil } + // check if go sdk was replaced + for _, req := range goModParsed.Replace { + if req.Old.Path == "github.com/grafana/grafana-plugin-sdk-go" && + req.New.Path != "github.com/grafana/grafana-plugin-sdk-go" { + pass.ReportResult( + pass.AnalyzerName, + goSdkNotUsed, + "Your plugin is using a custom or forked version of the Grafana Go SDK", + "Custom or forked version of Grafana Go SDK are not supported. Please use the latest Grafana Go SDK (github.com/grafana/grafana-plugin-sdk-go)", + ) + return nil, nil + } + } + return nil, nil } diff --git a/pkg/analysis/passes/sdkusage/sdkusage_test.go b/pkg/analysis/passes/sdkusage/sdkusage_test.go index e041cdab..c22622fe 100644 --- a/pkg/analysis/passes/sdkusage/sdkusage_test.go +++ b/pkg/analysis/passes/sdkusage/sdkusage_test.go @@ -27,7 +27,7 @@ func TestGoModNotFound(t *testing.T) { pass := &analysis.Pass{ RootDir: filepath.Join("./"), - ResultOf: map[*analysis.Analyzer]interface{}{ + ResultOf: map[*analysis.Analyzer]any{ sourcecode.Analyzer: filepath.Join("testdata", "nogomod"), nestedmetadata.Analyzer: nestedmetadata.Metadatamap{ "plugin.json": meta, @@ -58,7 +58,7 @@ func TestGoModNotParseable(t *testing.T) { pass := &analysis.Pass{ RootDir: filepath.Join("./"), - ResultOf: map[*analysis.Analyzer]interface{}{ + ResultOf: map[*analysis.Analyzer]any{ sourcecode.Analyzer: filepath.Join("testdata", "gomodwrong"), nestedmetadata.Analyzer: nestedmetadata.Metadatamap{ "plugin.json": meta, @@ -112,7 +112,7 @@ func TestValidGoMod(t *testing.T) { pass := &analysis.Pass{ RootDir: filepath.Join("./"), - ResultOf: map[*analysis.Analyzer]interface{}{ + ResultOf: map[*analysis.Analyzer]any{ sourcecode.Analyzer: filepath.Join("testdata", "validgomod"), nestedmetadata.Analyzer: nestedmetadata.Metadatamap{ "plugin.json": meta, @@ -138,7 +138,7 @@ func TestValidGoModWithNoGrafanaSdk(t *testing.T) { pass := &analysis.Pass{ RootDir: filepath.Join("./"), - ResultOf: map[*analysis.Analyzer]interface{}{ + ResultOf: map[*analysis.Analyzer]any{ sourcecode.Analyzer: filepath.Join("testdata", "nografanagosdk"), nestedmetadata.Analyzer: nestedmetadata.Metadatamap{ "plugin.json": meta, @@ -198,7 +198,7 @@ func TestTwoMonthsOldSdk(t *testing.T) { pass := &analysis.Pass{ RootDir: filepath.Join("./"), - ResultOf: map[*analysis.Analyzer]interface{}{ + ResultOf: map[*analysis.Analyzer]any{ sourcecode.Analyzer: filepath.Join("testdata", "sdk-2-months-old"), nestedmetadata.Analyzer: nestedmetadata.Metadatamap{ "plugin.json": meta, @@ -259,7 +259,7 @@ func TestFiveMonthsOld(t *testing.T) { pass := &analysis.Pass{ RootDir: filepath.Join("./"), - ResultOf: map[*analysis.Analyzer]interface{}{ + ResultOf: map[*analysis.Analyzer]any{ sourcecode.Analyzer: filepath.Join("testdata", "sdk-5-months-old"), nestedmetadata.Analyzer: nestedmetadata.Metadatamap{ "plugin.json": meta, @@ -278,3 +278,47 @@ func TestFiveMonthsOld(t *testing.T) { interceptor.Diagnostics[0].Title, ) } + +func TestReplacedSdk(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + + // mock latest request + httpmock.RegisterResponder( + "GET", + "https://api.github.com/repos/grafana/grafana-plugin-sdk-go/releases/latest", + httpmock.NewStringResponder( + 200, + `{ "tag_name": "v0.230.0", "published_at": "2024-05-09T10:03:16Z" }`, + ), + ) + + var interceptor testpassinterceptor.TestPassInterceptor + pluginJsonContent := []byte(`{ + "name": "my plugin name", + "backend": true, + "executable": "gx_plugin" + }`) + meta, err := testutils.JSONToMetadata(pluginJsonContent) + require.NoError(t, err) + + pass := &analysis.Pass{ + RootDir: filepath.Join("./"), + ResultOf: map[*analysis.Analyzer]any{ + sourcecode.Analyzer: filepath.Join("testdata", "replaced-sdk"), + nestedmetadata.Analyzer: nestedmetadata.Metadatamap{ + "plugin.json": meta, + }, + }, + Report: interceptor.ReportInterceptor(), + } + + _, err = Analyzer.Run(pass) + require.NoError(t, err) + require.Len(t, interceptor.Diagnostics, 1) + require.Equal( + t, + "Your plugin is using a custom or forked version of the Grafana Go SDK", + interceptor.Diagnostics[0].Title, + ) +} diff --git a/pkg/analysis/passes/sdkusage/testdata/replaced-sdk/go.mod b/pkg/analysis/passes/sdkusage/testdata/replaced-sdk/go.mod new file mode 100644 index 00000000..cb50f1ea --- /dev/null +++ b/pkg/analysis/passes/sdkusage/testdata/replaced-sdk/go.mod @@ -0,0 +1,9 @@ +module github.com/grafana/grafana-testing-replaced-sdk-datasource + +go 1.22 + +require ( + github.com/grafana/grafana-plugin-sdk-go v0.260.3 +) + +replace github.com/grafana/grafana-plugin-sdk-go v0.260.3 => ./grafana-plugin-sdk-go diff --git a/pkg/runner/runner.go b/pkg/runner/runner.go index a283da98..21d38c4a 100644 --- a/pkg/runner/runner.go +++ b/pkg/runner/runner.go @@ -72,6 +72,8 @@ func Check( seen[currentAnalyzer] = true + logme.DebugFln("Running analyzer %s", currentAnalyzer.Name) + // run all the dependencies of the analyzer for _, dep := range currentAnalyzer.Requires { // if dependency returned error. This analyzer should return error too @@ -99,7 +101,12 @@ func Check( return diagnostics, nil } -func initAnalyzers(analyzers []*analysis.Analyzer, cfg *Config, pluginId string, severityOverwrite analysis.Severity) { +func initAnalyzers( + analyzers []*analysis.Analyzer, + cfg *Config, + pluginId string, + severityOverwrite analysis.Severity, +) { for _, currentAnalyzer := range analyzers { // Inherit global config file analyzerEnabled := cfg.Global.Enabled