Public Dashboards: Add audit table (#54508)

This PR adds an audit table for public dashboards allowing a user to view all public dashboards on an instance of grafana. The public dashboards team is working on a proposal for adding RBAC support to the audit table for 9.3

Co-authored-by: juanicabanas <juan.cabanas@grafana.com>
This commit is contained in:
Jeff Levin
2022-10-12 21:36:05 -08:00
committed by GitHub
co-authored by juanicabanas
parent c7c640d903
commit cc27214dca
20 changed files with 516 additions and 44 deletions
+123 -32
View File
@@ -46,30 +46,129 @@ var userViewer = &user.SignedInUser{UserID: 3, OrgID: 1, OrgRole: org.RoleViewer
var userViewerRBAC = &user.SignedInUser{UserID: 4, OrgID: 1, OrgRole: org.RoleViewer, Login: "testViewerUserRBAC", Permissions: map[int64]map[string][]string{1: {dashboards.ActionDashboardsRead: {dashboards.ScopeDashboardsAll}}}}
var anonymousUser *user.SignedInUser
type JsonErrResponse struct {
Error string `json:"error"`
}
func TestAPIFeatureFlag(t *testing.T) {
testCases := []struct {
Name string
Method string
Path string
}{
{
Name: "API: Load Dashboard",
Method: http.MethodGet,
Path: "/api/public/dashboards/acbc123",
},
{
Name: "API: Query Dashboard",
Method: http.MethodGet,
Path: "/api/public/dashboards/abc123/panels/2/query",
},
{
Name: "API: List Dashboards",
Method: http.MethodGet,
Path: "/api/dashboards/public",
},
{
Name: "API: Get Public Dashboard Config",
Method: http.MethodPost,
Path: "/api/dashboards/uid/abc123/public-config",
},
{
Name: "API: Upate Public Dashboard",
Method: http.MethodPost,
Path: "/api/dashboards/uid/abc123/public-config",
},
}
for _, test := range testCases {
t.Run(test.Name, func(t *testing.T) {
cfg := setting.NewCfg()
cfg.RBACEnabled = false
service := publicdashboards.NewFakePublicDashboardService(t)
features := featuremgmt.WithFeatures()
testServer := setupTestServer(t, cfg, features, service, nil, userAdmin)
response := callAPI(testServer, test.Method, test.Path, nil, t)
assert.Equal(t, http.StatusNotFound, response.Code)
})
}
}
func TestAPIListPublicDashboard(t *testing.T) {
successResp := []PublicDashboardListResponse{
{
Uid: "1234asdfasdf",
AccessToken: "asdfasdf",
DashboardUid: "abc1234",
IsEnabled: true,
},
}
testCases := []struct {
Name string
User *user.SignedInUser
Response []PublicDashboardListResponse
ResponseErr error
ExpectedHttpResponse int
}{
{
Name: "Anonymous user cannot list dashboards",
User: anonymousUser,
Response: successResp,
ResponseErr: nil,
ExpectedHttpResponse: http.StatusUnauthorized,
},
{
Name: "User viewer can see public dashboards",
User: userViewer,
Response: successResp,
ResponseErr: nil,
ExpectedHttpResponse: http.StatusOK,
},
{
Name: "Handles Service error",
User: userViewer,
Response: nil,
ResponseErr: errors.New("error, service broken"),
ExpectedHttpResponse: http.StatusInternalServerError,
},
}
for _, test := range testCases {
t.Run(test.Name, func(t *testing.T) {
service := publicdashboards.NewFakePublicDashboardService(t)
service.On("ListPublicDashboards", mock.Anything, mock.Anything).
Return(test.Response, test.ResponseErr).Maybe()
cfg := setting.NewCfg()
cfg.RBACEnabled = false
features := featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards)
testServer := setupTestServer(t, cfg, features, service, nil, test.User)
response := callAPI(testServer, http.MethodGet, "/api/dashboards/public", nil, t)
assert.Equal(t, test.ExpectedHttpResponse, response.Code)
if test.ExpectedHttpResponse == http.StatusOK {
var jsonResp []PublicDashboardListResponse
err := json.Unmarshal(response.Body.Bytes(), &jsonResp)
require.NoError(t, err)
assert.Equal(t, jsonResp[0].Uid, "1234asdfasdf")
}
if test.ResponseErr != nil {
var errResp JsonErrResponse
err := json.Unmarshal(response.Body.Bytes(), &errResp)
require.NoError(t, err)
assert.Equal(t, "error, service broken", errResp.Error)
service.AssertNotCalled(t, "ListPublicDashboards")
}
})
}
}
func TestAPIGetPublicDashboard(t *testing.T) {
t.Run("It should 404 if featureflag is not enabled", func(t *testing.T) {
cfg := setting.NewCfg()
cfg.RBACEnabled = false
service := publicdashboards.NewFakePublicDashboardService(t)
service.On("GetPublicDashboard", mock.Anything, mock.AnythingOfType("string")).
Return(&PublicDashboard{}, &models.Dashboard{}, nil).Maybe()
service.On("GetPublicDashboardConfig", mock.Anything, mock.AnythingOfType("int64"), mock.AnythingOfType("string")).
Return(&PublicDashboard{}, nil).Maybe()
testServer := setupTestServer(t, cfg, featuremgmt.WithFeatures(), service, nil, anonymousUser)
response := callAPI(testServer, http.MethodGet, "/api/public/dashboards", nil, t)
assert.Equal(t, http.StatusNotFound, response.Code)
response = callAPI(testServer, http.MethodGet, "/api/public/dashboards/asdf", nil, t)
assert.Equal(t, http.StatusNotFound, response.Code)
// control set. make sure routes are mounted
testServer = setupTestServer(t, cfg, featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards), service, nil, userAdmin)
response = callAPI(testServer, http.MethodGet, "/api/public/dashboards/asdf", nil, t)
assert.NotEqual(t, http.StatusNotFound, response.Code)
})
DashboardUid := "dashboard-abcd1234"
token, err := uuid.NewRandom()
require.NoError(t, err)
@@ -138,9 +237,7 @@ func TestAPIGetPublicDashboard(t *testing.T) {
assert.Equal(t, false, dashResp.Meta.CanDelete)
assert.Equal(t, false, dashResp.Meta.CanSave)
} else {
var errResp struct {
Error string `json:"error"`
}
var errResp JsonErrResponse
err := json.Unmarshal(response.Body.Bytes(), &errResp)
require.NoError(t, err)
assert.Equal(t, test.Err.Error(), errResp.Error)
@@ -435,12 +532,6 @@ func TestAPIQueryPublicDashboard(t *testing.T) {
return testServer, service
}
t.Run("Status code is 404 when feature toggle is disabled", func(t *testing.T) {
server, _ := setup(false)
resp := callAPI(server, http.MethodPost, "/api/public/dashboards/abc123/panels/2/query", strings.NewReader("{}"), t)
require.Equal(t, http.StatusNotFound, resp.Code)
})
t.Run("Status code is 400 when the panel ID is invalid", func(t *testing.T) {
server, _ := setup(true)
resp := callAPI(server, http.MethodPost, "/api/public/dashboards/abc123/panels/notanumber/query", strings.NewReader("{}"), t)