From 7add63ff82b627fdfdc49e1ed247dc14d14b8dce Mon Sep 17 00:00:00 2001 From: Will Browne Date: Tue, 30 Sep 2025 15:09:43 +0100 Subject: [PATCH] [release-11.6.7] Plugins: Dependencies do not inherit parent URL for preinstall (#111801) Plugins: Dependencies do not inherit parent URL for preinstall (#111762) dependencies dont inehrit parent url for preinstall (cherry picked from commit 073338ec295bf26eede4dba42906c348a0aa71bf) --- pkg/plugins/manager/installer.go | 2 +- pkg/plugins/manager/installer_test.go | 64 +++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/pkg/plugins/manager/installer.go b/pkg/plugins/manager/installer.go index 6c5713c55b0..4d514136a9a 100644 --- a/pkg/plugins/manager/installer.go +++ b/pkg/plugins/manager/installer.go @@ -68,7 +68,7 @@ func (m *PluginInstaller) Add(ctx context.Context, pluginID, version string, opt for _, dep := range archive.Dependencies { m.log.Info(fmt.Sprintf("Fetching %s dependency %s...", pluginID, dep.ID)) - err = m.Add(ctx, dep.ID, dep.Version, opts) + err = m.Add(ctx, dep.ID, "", plugins.NewAddOpts(opts.GrafanaVersion(), opts.OS(), opts.Arch(), "")) if err != nil { var dupeErr plugins.DuplicateError if errors.As(err, &dupeErr) { diff --git a/pkg/plugins/manager/installer_test.go b/pkg/plugins/manager/installer_test.go index ae2025445e1..5148ea30ccb 100644 --- a/pkg/plugins/manager/installer_test.go +++ b/pkg/plugins/manager/installer_test.go @@ -384,6 +384,70 @@ func TestPluginManager_Add_Remove(t *testing.T) { require.NoError(t, err) require.Equal(t, []string{"test-plugin.zip"}, loadedPaths) }) + + t.Run("Dependencies don't inherit parent plugin's URL during installation", func(t *testing.T) { + const ( + parentPluginID = "parent-plugin" + depPluginID = "dependency-plugin" + parentURL = "https://example.com/parent-plugin.zip" + ) + + var loadedPaths []string + loader := &fakes.FakeLoader{ + LoadFunc: func(ctx context.Context, src plugins.PluginSource) ([]*plugins.Plugin, error) { + loadedPaths = append(loadedPaths, src.PluginURIs(ctx)...) + return []*plugins.Plugin{}, nil + }, + } + + // Track which methods are called to ensure dependencies use catalog, not URL + urlMethodCalled := false + catalogMethodCalled := false + + pluginRepo := &fakes.FakePluginRepo{ + GetPluginArchiveByURLFunc: func(_ context.Context, url string, _ repo.CompatOpts) (*repo.PluginArchive, error) { + urlMethodCalled = true + require.Equal(t, parentURL, url, "URL method should only be called for parent plugin") + return &repo.PluginArchive{File: &zip.ReadCloser{Reader: zip.Reader{File: []*zip.File{{ + FileHeader: zip.FileHeader{Name: "parent-plugin.zip"}, + }}}}}, nil + }, + GetPluginArchiveFunc: func(_ context.Context, id, version string, _ repo.CompatOpts) (*repo.PluginArchive, error) { + catalogMethodCalled = true + require.Equal(t, depPluginID, id, "Catalog method should only be called for dependency plugin") + return &repo.PluginArchive{File: &zip.ReadCloser{Reader: zip.Reader{File: []*zip.File{{ + FileHeader: zip.FileHeader{Name: "dependency-plugin.zip"}, + }}}}}, nil + }, + } + + fs := &fakes.FakePluginStorage{ + ExtractFunc: func(_ context.Context, id string, _ storage.DirNameGeneratorFunc, z *zip.ReadCloser) (*storage.ExtractedPluginArchive, error) { + switch id { + case parentPluginID: + return &storage.ExtractedPluginArchive{ + ID: parentPluginID, + Dependencies: []*storage.Dependency{{ID: depPluginID}}, + Path: "parent-plugin.zip", + }, nil + case depPluginID: + return &storage.ExtractedPluginArchive{ + ID: depPluginID, + Path: "dependency-plugin.zip", + }, nil + default: + return nil, fmt.Errorf("unknown plugin %s", id) + } + }, + } + + inst := New(fakes.NewFakePluginRegistry(), loader, pluginRepo, fs, storage.SimpleDirNameGeneratorFunc, &fakes.FakeAuthService{}) + err := inst.Add(context.Background(), parentPluginID, "", plugins.NewAddOpts("10.0.0", runtime.GOOS, runtime.GOARCH, parentURL)) + require.NoError(t, err) + require.Equal(t, []string{"dependency-plugin.zip", "parent-plugin.zip"}, loadedPaths) + require.True(t, urlMethodCalled) + require.True(t, catalogMethodCalled) + }) } func createPlugin(t *testing.T, pluginID string, class plugins.Class, managed, backend bool, cbs ...func(*plugins.Plugin)) *plugins.Plugin {