From b74b1d5d4f43be899b88b26af40f38d19b413fbe Mon Sep 17 00:00:00 2001
From: Mihai Turdean <6640685+mihai-turdean@users.noreply.github.com>
Date: Mon, 2 Feb 2026 23:59:08 -0800
Subject: [PATCH] Datasources: Fix permissions cleanup when deleting datasource
 by name (#117289)

* Fix missing UID when deleting datasource by name

* Add test
---
 pkg/api/datasources.go      |  2 +-
 pkg/api/datasources_test.go | 54 +++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/pkg/api/datasources.go b/pkg/api/datasources.go
index 0eef6a7ce16..456f87f42b5 100644
--- a/pkg/api/datasources.go
+++ b/pkg/api/datasources.go
@@ -304,7 +304,7 @@ func (hs *HTTPServer) DeleteDataSourceByName(c *contextmodel.ReqContext) respons
 		return response.Error(http.StatusForbidden, "Cannot delete read-only data source", nil)
 	}
 
-	cmd := &datasources.DeleteDataSourceCommand{Name: name, OrgID: c.SignedInUser.GetOrgID()}
+	cmd := &datasources.DeleteDataSourceCommand{Name: name, OrgID: c.SignedInUser.GetOrgID(), UID: dataSource.UID}
 	err = hs.DataSourcesService.DeleteDataSource(c.Req.Context(), cmd)
 	if err != nil {
 		if errors.As(err, &secretsPluginError) {
diff --git a/pkg/api/datasources_test.go b/pkg/api/datasources_test.go
index fa057d3ccd5..ae426b73f32 100644
--- a/pkg/api/datasources_test.go
+++ b/pkg/api/datasources_test.go
@@ -446,6 +446,56 @@ func TestAPI_datasources_AccessControl(t *testing.T) {
 	}
 }
 
+func TestDeleteDataSourceByName_IncludesUIDForPermissions(t *testing.T) {
+	t.Run("should include UID when deleting datasource by name", func(t *testing.T) {
+		const dsName = "test-datasource"
+		const dsUID = "test-uid-12345"
+		const orgID int64 = 1
+
+		var capturedDeleteCmd *datasources.DeleteDataSourceCommand
+
+		// Mock datasource service
+		mockDsService := &dataSourcesServiceMock{
+			expectedDatasource: &datasources.DataSource{
+				Name:  dsName,
+				UID:   dsUID,
+				OrgID: orgID,
+			},
+			mockDeleteDataSource: func(ctx context.Context, cmd *datasources.DeleteDataSourceCommand) error {
+				capturedDeleteCmd = cmd
+				return nil
+			},
+		}
+
+		hs := &HTTPServer{
+			Cfg:                setting.NewCfg(),
+			pluginStore:        &pluginstore.FakePluginStore{},
+			DataSourcesService: mockDsService,
+			Live:               newTestLive(t),
+		}
+
+		// Create scenario context
+		sc := setupScenarioContext(t, "/api/datasources/name/"+dsName)
+		sc.m.Delete(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
+			c.Req = web.SetURLParams(c.Req, map[string]string{":name": dsName})
+			c.SignedInUser = authedUserWithPermissions(orgID, 1, []ac.Permission{})
+			c.OrgID = orgID
+			return hs.DeleteDataSourceByName(c)
+		}))
+
+		sc.fakeReqWithParams("DELETE", sc.url, map[string]string{":name": dsName}).exec()
+
+		// Verify the response was successful
+		assert.Equal(t, 200, sc.resp.Code)
+
+		// Verify that DeleteDataSource was called with the UID populated
+		require.NotNil(t, capturedDeleteCmd, "DeleteDataSource should have been called")
+		assert.Equal(t, dsName, capturedDeleteCmd.Name, "Command should have datasource name")
+		assert.Equal(t, dsUID, capturedDeleteCmd.UID, "Command should have datasource UID for permissions cleanup")
+		assert.Equal(t, orgID, capturedDeleteCmd.OrgID, "Command should have correct org ID")
+	})
+}
+
 type dataSourcesServiceMock struct {
 	datasources.DataSourceService
 
@@ -454,6 +504,7 @@ type dataSourcesServiceMock struct {
 	expectedError       error
 
 	mockUpdateDataSource func(ctx context.Context, cmd *datasources.UpdateDataSourceCommand) (*datasources.DataSource, error)
+	mockDeleteDataSource func(ctx context.Context, cmd *datasources.DeleteDataSourceCommand) error
 }
 
 func (m *dataSourcesServiceMock) GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) (*datasources.DataSource, error) {
@@ -469,6 +520,9 @@ func (m *dataSourcesServiceMock) GetDataSourcesByType(ctx context.Context, query
 }
 
 func (m *dataSourcesServiceMock) DeleteDataSource(ctx context.Context, cmd *datasources.DeleteDataSourceCommand) error {
+	if m.mockDeleteDataSource != nil {
+		return m.mockDeleteDataSource(ctx, cmd)
+	}
 	return m.expectedError
 }
 
-- 
2.51.0

