diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 556eb1c28e1..6b25d977ff1 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -458,6 +458,12 @@ func (hs *HTTPServer) InstallPlugin(c *contextmodel.ReqContext) response.Respons hs.log.Info("Plugin install/update requested", "pluginId", pluginID, "user", c.Login) + for _, preinstalled := range hs.Cfg.InstallPlugins { + if preinstalled.ID == pluginID && preinstalled.Version != "" { + return response.Error(http.StatusConflict, "Cannot update a pinned pre-installed plugin", nil) + } + } + compatOpts := plugins.NewCompatOpts(hs.Cfg.BuildVersion, runtime.GOOS, runtime.GOARCH) err := hs.pluginInstaller.Add(c.Req.Context(), pluginID, dto.Version, compatOpts) if err != nil { @@ -496,6 +502,12 @@ func (hs *HTTPServer) UninstallPlugin(c *contextmodel.ReqContext) response.Respo return response.Error(http.StatusNotFound, "Plugin not installed", nil) } + for _, preinstalled := range hs.Cfg.InstallPlugins { + if preinstalled.ID == pluginID { + return response.Error(http.StatusConflict, "Cannot uninstall a pre-installed plugin", nil) + } + } + err := hs.pluginInstaller.Remove(c.Req.Context(), pluginID, plugin.Info.Version) if err != nil { if errors.Is(err, plugins.ErrPluginNotInstalled) { diff --git a/pkg/api/plugins_test.go b/pkg/api/plugins_test.go index b29b0fdfa00..d1d44affb75 100644 --- a/pkg/api/plugins_test.go +++ b/pkg/api/plugins_test.go @@ -55,7 +55,7 @@ func Test_PluginsInstallAndUninstall(t *testing.T) { canInstall := []ac.Permission{{Action: pluginaccesscontrol.ActionInstall}} cannotInstall := []ac.Permission{{Action: "plugins:cannotinstall"}} - pluginID := "grafana-test-datasource" + pluginID := "" localOrg := int64(1) globalOrg := int64(ac.GlobalOrgID) @@ -66,6 +66,7 @@ func Test_PluginsInstallAndUninstall(t *testing.T) { pluginAdminEnabled bool pluginAdminExternalManageEnabled bool singleOrganization bool + preInstalledPlugin bool } tcs := []testCase{ {expectedCode: http.StatusNotFound, permissionOrg: globalOrg, permissions: canInstall, pluginAdminEnabled: true, pluginAdminExternalManageEnabled: true}, @@ -76,6 +77,7 @@ func Test_PluginsInstallAndUninstall(t *testing.T) { {expectedCode: http.StatusForbidden, permissionOrg: localOrg, permissions: canInstall, pluginAdminEnabled: true, pluginAdminExternalManageEnabled: false}, {expectedCode: http.StatusForbidden, permissionOrg: localOrg, permissions: cannotInstall, pluginAdminEnabled: true, pluginAdminExternalManageEnabled: false, singleOrganization: true}, {expectedCode: http.StatusOK, permissionOrg: localOrg, permissions: canInstall, pluginAdminEnabled: true, pluginAdminExternalManageEnabled: false, singleOrganization: true}, + {expectedCode: http.StatusConflict, permissionOrg: globalOrg, permissions: canInstall, pluginAdminEnabled: true, pluginAdminExternalManageEnabled: false, preInstalledPlugin: true}, } testName := func(action string, tc testCase) string { @@ -84,11 +86,16 @@ func Test_PluginsInstallAndUninstall(t *testing.T) { } for _, tc := range tcs { + pluginID = "grafana-test-datasource" + if tc.preInstalledPlugin { + pluginID = "grafana-preinstalled-datasource" + } server := SetupAPITestServer(t, func(hs *HTTPServer) { hs.Cfg = setting.NewCfg() hs.Cfg.PluginAdminEnabled = tc.pluginAdminEnabled hs.Cfg.PluginAdminExternalManageEnabled = tc.pluginAdminExternalManageEnabled hs.Cfg.RBAC.SingleOrganization = tc.singleOrganization + hs.Cfg.InstallPlugins = []setting.InstallPlugin{{ID: "grafana-preinstalled-datasource", Version: "1.0.0"}} hs.orgService = &orgtest.FakeOrgService{ExpectedOrg: &org.Org{}} hs.accesscontrolService = &actest.FakeService{}