Alerting: Fix contact point export 500 error and notifications/receivers missing settings (#90342)

* Regression test

* Fix 500 error when exporting redacted receivers

* Fix tests to check permissions
This commit is contained in:
Matthew Jacobson
2024-07-12 11:42:22 -04:00
committed by GitHub
parent 5d8ca38b9b
commit b7767c79e7
7 changed files with 130 additions and 61 deletions

View File

@@ -135,7 +135,7 @@ func (srv *ProvisioningSrv) RouteGetContactPoints(c *contextmodel.ReqContext) re
Name: c.Query("name"), Name: c.Query("name"),
OrgID: c.SignedInUser.GetOrgID(), OrgID: c.SignedInUser.GetOrgID(),
} }
cps, err := srv.contactPointService.GetContactPoints(c.Req.Context(), q, nil) cps, err := srv.contactPointService.GetContactPoints(c.Req.Context(), q, c.SignedInUser)
if err != nil { if err != nil {
if errors.Is(err, provisioning.ErrPermissionDenied) { if errors.Is(err, provisioning.ErrPermissionDenied) {
return ErrResp(http.StatusForbidden, err, "") return ErrResp(http.StatusForbidden, err, "")

View File

@@ -1473,9 +1473,26 @@ func TestProvisioningApi(t *testing.T) {
} }
func TestProvisioningApiContactPointExport(t *testing.T) { func TestProvisioningApiContactPointExport(t *testing.T) {
createTestEnv := func(t *testing.T, testConfig string) testEnvironment {
env := createTestEnv(t, testConfig)
env.ac = &recordingAccessControlFake{
Callback: func(user *user.SignedInUser, evaluator accesscontrol.Evaluator) (bool, error) {
if strings.Contains(evaluator.String(), accesscontrol.ActionAlertingNotificationsRead) {
return true, nil
}
if strings.Contains(evaluator.String(), accesscontrol.ActionAlertingReceiversList) {
return true, nil
}
return false, nil
},
}
return env
}
t.Run("contact point export", func(t *testing.T) { t.Run("contact point export", func(t *testing.T) {
t.Run("are present, GET returns 200", func(t *testing.T) { t.Run("are present, GET returns 200", func(t *testing.T) {
sut := createProvisioningSrvSut(t) env := createTestEnv(t, testConfig)
sut := createProvisioningSrvSutFromEnv(t, &env)
rc := createTestRequestCtx() rc := createTestRequestCtx()
response := sut.RouteGetContactPointsExport(&rc) response := sut.RouteGetContactPointsExport(&rc)
@@ -1484,7 +1501,8 @@ func TestProvisioningApiContactPointExport(t *testing.T) {
}) })
t.Run("accept header contains yaml, GET returns text yaml", func(t *testing.T) { t.Run("accept header contains yaml, GET returns text yaml", func(t *testing.T) {
sut := createProvisioningSrvSut(t) env := createTestEnv(t, testConfig)
sut := createProvisioningSrvSutFromEnv(t, &env)
rc := createTestRequestCtx() rc := createTestRequestCtx()
rc.Context.Req.Header.Add("Accept", "application/yaml") rc.Context.Req.Header.Add("Accept", "application/yaml")
@@ -1496,7 +1514,8 @@ func TestProvisioningApiContactPointExport(t *testing.T) {
}) })
t.Run("accept header contains json, GET returns json", func(t *testing.T) { t.Run("accept header contains json, GET returns json", func(t *testing.T) {
sut := createProvisioningSrvSut(t) env := createTestEnv(t, testConfig)
sut := createProvisioningSrvSutFromEnv(t, &env)
rc := createTestRequestCtx() rc := createTestRequestCtx()
rc.Context.Req.Header.Add("Accept", "application/json") rc.Context.Req.Header.Add("Accept", "application/json")
@@ -1508,7 +1527,8 @@ func TestProvisioningApiContactPointExport(t *testing.T) {
}) })
t.Run("accept header contains json and yaml, GET returns json", func(t *testing.T) { t.Run("accept header contains json and yaml, GET returns json", func(t *testing.T) {
sut := createProvisioningSrvSut(t) env := createTestEnv(t, testConfig)
sut := createProvisioningSrvSutFromEnv(t, &env)
rc := createTestRequestCtx() rc := createTestRequestCtx()
rc.Context.Req.Header.Add("Accept", "application/json, application/yaml") rc.Context.Req.Header.Add("Accept", "application/json, application/yaml")
@@ -1520,7 +1540,8 @@ func TestProvisioningApiContactPointExport(t *testing.T) {
}) })
t.Run("query param download=true, GET returns content disposition attachment", func(t *testing.T) { t.Run("query param download=true, GET returns content disposition attachment", func(t *testing.T) {
sut := createProvisioningSrvSut(t) env := createTestEnv(t, testConfig)
sut := createProvisioningSrvSutFromEnv(t, &env)
rc := createTestRequestCtx() rc := createTestRequestCtx()
rc.Context.Req.Form.Set("download", "true") rc.Context.Req.Form.Set("download", "true")
@@ -1532,7 +1553,8 @@ func TestProvisioningApiContactPointExport(t *testing.T) {
}) })
t.Run("query param download=false, GET returns empty content disposition", func(t *testing.T) { t.Run("query param download=false, GET returns empty content disposition", func(t *testing.T) {
sut := createProvisioningSrvSut(t) env := createTestEnv(t, testConfig)
sut := createProvisioningSrvSutFromEnv(t, &env)
rc := createTestRequestCtx() rc := createTestRequestCtx()
rc.Context.Req.Form.Set("download", "false") rc.Context.Req.Form.Set("download", "false")
@@ -1544,7 +1566,8 @@ func TestProvisioningApiContactPointExport(t *testing.T) {
}) })
t.Run("query param download not set, GET returns empty content disposition", func(t *testing.T) { t.Run("query param download not set, GET returns empty content disposition", func(t *testing.T) {
sut := createProvisioningSrvSut(t) env := createTestEnv(t, testConfig)
sut := createProvisioningSrvSutFromEnv(t, &env)
rc := createTestRequestCtx() rc := createTestRequestCtx()
response := sut.RouteGetContactPointsExport(&rc) response := sut.RouteGetContactPointsExport(&rc)

View File

@@ -64,13 +64,7 @@ func NewReceiverService(
} }
func (rs *ReceiverService) shouldDecrypt(ctx context.Context, user identity.Requester, reqDecrypt bool) (bool, error) { func (rs *ReceiverService) shouldDecrypt(ctx context.Context, user identity.Requester, reqDecrypt bool) (bool, error) {
// TODO: migrate to new permission decryptAccess, err := rs.hasReadDecrypted(ctx, user)
eval := accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionAlertingReceiversReadSecrets),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningReadSecrets),
)
decryptAccess, err := rs.ac.Evaluate(ctx, user, eval)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -82,6 +76,31 @@ func (rs *ReceiverService) shouldDecrypt(ctx context.Context, user identity.Requ
return decryptAccess && reqDecrypt, nil return decryptAccess && reqDecrypt, nil
} }
// hasReadDecrypted checks if the user has permission to read decrypted secure settings.
func (rs *ReceiverService) hasReadDecrypted(ctx context.Context, user identity.Requester) (bool, error) {
return rs.ac.Evaluate(ctx, user, accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionAlertingReceiversReadSecrets),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningReadSecrets), // TODO: Add scope all when we implement FGAC.
))
}
// hasReadRedacted checks if the user has permission to read redacted secure settings.
func (rs *ReceiverService) hasReadRedacted(ctx context.Context, user identity.Requester) (bool, error) {
return rs.ac.Evaluate(ctx, user, accesscontrol.EvalAny(
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningRead),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingProvisioningReadSecrets),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingNotificationsProvisioningRead),
accesscontrol.EvalPermission(accesscontrol.ActionAlertingNotificationsRead),
//accesscontrol.EvalPermission(accesscontrol.ActionAlertingReceiversRead, ScopeReceiversProvider.GetResourceAllScope()), // TODO: Add new permissions.
//accesscontrol.EvalPermission(accesscontrol.ActionAlertingReceiversReadSecrets, ScopeReceiversProvider.GetResourceAllScope(),
))
}
// hasList checks if the user has permission to list receivers.
func (rs *ReceiverService) hasList(ctx context.Context, user identity.Requester) (bool, error) {
return rs.ac.Evaluate(ctx, user, accesscontrol.EvalPermission(accesscontrol.ActionAlertingReceiversList))
}
// GetReceiver returns a receiver by name. // GetReceiver returns a receiver by name.
// The receiver's secure settings are decrypted if requested and the user has access to do so. // The receiver's secure settings are decrypted if requested and the user has access to do so.
func (rs *ReceiverService) GetReceiver(ctx context.Context, q models.GetReceiverQuery, user identity.Requester) (definitions.GettableApiReceiver, error) { func (rs *ReceiverService) GetReceiver(ctx context.Context, q models.GetReceiverQuery, user identity.Requester) (definitions.GettableApiReceiver, error) {
@@ -144,12 +163,22 @@ func (rs *ReceiverService) GetReceivers(ctx context.Context, q models.GetReceive
return nil, err return nil, err
} }
eval := accesscontrol.EvalPermission(accesscontrol.ActionAlertingReceiversList) readRedactedAccess, err := rs.hasReadRedacted(ctx, user)
listAccess, err := rs.ac.Evaluate(ctx, user, eval)
if err != nil { if err != nil {
return nil, err return nil, err
} }
listAccess, err := rs.hasList(ctx, user)
if err != nil {
return nil, err
}
// User doesn't have any permissions on the receivers.
// This is mostly a safeguard as it should not be possible with current API endpoints + middleware authentication.
if !listAccess && !readRedactedAccess {
return nil, ErrPermissionDenied
}
var output []definitions.GettableApiReceiver var output []definitions.GettableApiReceiver
for i := q.Offset; i < len(cfg.AlertmanagerConfig.Receivers); i++ { for i := q.Offset; i < len(cfg.AlertmanagerConfig.Receivers); i++ {
r := cfg.AlertmanagerConfig.Receivers[i] r := cfg.AlertmanagerConfig.Receivers[i]
@@ -163,7 +192,11 @@ func (rs *ReceiverService) GetReceivers(ctx context.Context, q models.GetReceive
} }
decryptFn := rs.decryptOrRedact(ctx, decrypt, r.Name, "") decryptFn := rs.decryptOrRedact(ctx, decrypt, r.Name, "")
listOnly := !decrypt && listAccess
// Only has permission to list. This reduces from:
// - Has List permission
// - Doesn't have ReadRedacted (or ReadDecrypted permission since it's a subset).
listOnly := !readRedactedAccess
res, err := PostableToGettableApiReceiver(r, provenances, decryptFn, listOnly) res, err := PostableToGettableApiReceiver(r, provenances, decryptFn, listOnly)
if err != nil { if err != nil {

View File

@@ -13,7 +13,6 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
"github.com/grafana/grafana/pkg/services/authz/zanzana" "github.com/grafana/grafana/pkg/services/authz/zanzana"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
@@ -29,10 +28,16 @@ func TestReceiverService_GetReceiver(t *testing.T) {
sqlStore := db.InitTestDB(t) sqlStore := db.InitTestDB(t)
secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
redactedUser := &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
1: {
accesscontrol.ActionAlertingProvisioningRead: nil,
},
}}
t.Run("service gets receiver from AM config", func(t *testing.T) { t.Run("service gets receiver from AM config", func(t *testing.T) {
sut := createReceiverServiceSut(t, secretsService) sut := createReceiverServiceSut(t, secretsService)
Receiver, err := sut.GetReceiver(context.Background(), singleQ(1, "slack receiver"), nil) Receiver, err := sut.GetReceiver(context.Background(), singleQ(1, "slack receiver"), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, "slack receiver", Receiver.Name) require.Equal(t, "slack receiver", Receiver.Name)
require.Len(t, Receiver.GrafanaManagedReceivers, 1) require.Len(t, Receiver.GrafanaManagedReceivers, 1)
@@ -42,7 +47,7 @@ func TestReceiverService_GetReceiver(t *testing.T) {
t.Run("service returns error when receiver does not exist", func(t *testing.T) { t.Run("service returns error when receiver does not exist", func(t *testing.T) {
sut := createReceiverServiceSut(t, secretsService) sut := createReceiverServiceSut(t, secretsService)
_, err := sut.GetReceiver(context.Background(), singleQ(1, "nonexistent"), nil) _, err := sut.GetReceiver(context.Background(), singleQ(1, "nonexistent"), redactedUser)
require.ErrorIs(t, err, ErrNotFound) require.ErrorIs(t, err, ErrNotFound)
}) })
} }
@@ -51,10 +56,16 @@ func TestReceiverService_GetReceivers(t *testing.T) {
sqlStore := db.InitTestDB(t) sqlStore := db.InitTestDB(t)
secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
redactedUser := &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
1: {
accesscontrol.ActionAlertingProvisioningRead: nil,
},
}}
t.Run("service gets receivers from AM config", func(t *testing.T) { t.Run("service gets receivers from AM config", func(t *testing.T) {
sut := createReceiverServiceSut(t, secretsService) sut := createReceiverServiceSut(t, secretsService)
Receivers, err := sut.GetReceivers(context.Background(), multiQ(1), nil) Receivers, err := sut.GetReceivers(context.Background(), multiQ(1), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, Receivers, 2) require.Len(t, Receivers, 2)
require.Equal(t, "grafana-default-email", Receivers[0].Name) require.Equal(t, "grafana-default-email", Receivers[0].Name)
@@ -64,7 +75,7 @@ func TestReceiverService_GetReceivers(t *testing.T) {
t.Run("service filters receivers by name", func(t *testing.T) { t.Run("service filters receivers by name", func(t *testing.T) {
sut := createReceiverServiceSut(t, secretsService) sut := createReceiverServiceSut(t, secretsService)
Receivers, err := sut.GetReceivers(context.Background(), multiQ(1, "slack receiver"), nil) Receivers, err := sut.GetReceivers(context.Background(), multiQ(1, "slack receiver"), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, Receivers, 1) require.Len(t, Receivers, 1)
require.Equal(t, "slack receiver", Receivers[0].Name) require.Equal(t, "slack receiver", Receivers[0].Name)
@@ -74,7 +85,6 @@ func TestReceiverService_GetReceivers(t *testing.T) {
func TestReceiverService_DecryptRedact(t *testing.T) { func TestReceiverService_DecryptRedact(t *testing.T) {
sqlStore := db.InitTestDB(t) sqlStore := db.InitTestDB(t)
secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
ac := acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient())
getMethods := []string{"single", "multi"} getMethods := []string{"single", "multi"}
@@ -129,7 +139,6 @@ func TestReceiverService_DecryptRedact(t *testing.T) {
for _, method := range getMethods { for _, method := range getMethods {
t.Run(fmt.Sprintf("%s %s", tc.name, method), func(t *testing.T) { t.Run(fmt.Sprintf("%s %s", tc.name, method), func(t *testing.T) {
sut := createReceiverServiceSut(t, secretsService) sut := createReceiverServiceSut(t, secretsService)
sut.ac = ac
var res definitions.GettableApiReceiver var res definitions.GettableApiReceiver
var err error var err error
@@ -174,7 +183,7 @@ func createReceiverServiceSut(t *testing.T, encryptSvc secrets.Service) *Receive
provisioningStore := fakes.NewFakeProvisioningStore() provisioningStore := fakes.NewFakeProvisioningStore()
return &ReceiverService{ return &ReceiverService{
actest.FakeAccessControl{}, acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()),
provisioningStore, provisioningStore,
store, store,
encryptSvc, encryptSvc,

View File

@@ -47,9 +47,13 @@ func PostableGrafanaReceiverToEmbeddedContactPoint(contactPoint *definitions.Pos
} }
func GettableGrafanaReceiverToEmbeddedContactPoint(r *definitions.GettableGrafanaReceiver) (definitions.EmbeddedContactPoint, error) { func GettableGrafanaReceiverToEmbeddedContactPoint(r *definitions.GettableGrafanaReceiver) (definitions.EmbeddedContactPoint, error) {
settingJson, err := simplejson.NewJson(r.Settings) settingJson := simplejson.New()
if err != nil { if r.Settings != nil {
return definitions.EmbeddedContactPoint{}, err var err error
settingJson, err = simplejson.NewJson(r.Settings)
if err != nil {
return definitions.EmbeddedContactPoint{}, err
}
} }
for k := range r.SecureFields { for k := range r.SecureFields {

View File

@@ -16,7 +16,6 @@ import (
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
"github.com/grafana/grafana/pkg/services/authz/zanzana" "github.com/grafana/grafana/pkg/services/authz/zanzana"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
@@ -33,10 +32,17 @@ import (
func TestContactPointService(t *testing.T) { func TestContactPointService(t *testing.T) {
sqlStore := db.InitTestDB(t) sqlStore := db.InitTestDB(t)
secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
redactedUser := &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
1: {
accesscontrol.ActionAlertingProvisioningRead: nil,
},
}}
t.Run("service gets contact points from AM config", func(t *testing.T) { t.Run("service gets contact points from AM config", func(t *testing.T) {
sut := createContactPointServiceSut(t, secretsService) sut := createContactPointServiceSut(t, secretsService)
cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1), nil) cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, cps, 2) require.Len(t, cps, 2)
@@ -47,7 +53,7 @@ func TestContactPointService(t *testing.T) {
t.Run("service filters contact points by name", func(t *testing.T) { t.Run("service filters contact points by name", func(t *testing.T) {
sut := createContactPointServiceSut(t, secretsService) sut := createContactPointServiceSut(t, secretsService)
cps, err := sut.GetContactPoints(context.Background(), cpsQueryWithName(1, "slack receiver"), nil) cps, err := sut.GetContactPoints(context.Background(), cpsQueryWithName(1, "slack receiver"), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, cps, 1) require.Len(t, cps, 1)
@@ -57,7 +63,7 @@ func TestContactPointService(t *testing.T) {
t.Run("service filters contact points by name, returns empty when no match", func(t *testing.T) { t.Run("service filters contact points by name, returns empty when no match", func(t *testing.T) {
sut := createContactPointServiceSut(t, secretsService) sut := createContactPointServiceSut(t, secretsService)
cps, err := sut.GetContactPoints(context.Background(), cpsQueryWithName(1, "unknown"), nil) cps, err := sut.GetContactPoints(context.Background(), cpsQueryWithName(1, "unknown"), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, cps, 0) require.Len(t, cps, 0)
@@ -70,7 +76,7 @@ func TestContactPointService(t *testing.T) {
_, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) _, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI)
require.NoError(t, err) require.NoError(t, err)
cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1), nil) cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, cps, 3) require.Len(t, cps, 3)
require.Equal(t, "test-contact-point", cps[2].Name) require.Equal(t, "test-contact-point", cps[2].Name)
@@ -86,7 +92,7 @@ func TestContactPointService(t *testing.T) {
_, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) _, err := sut.CreateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI)
require.NoError(t, err) require.NoError(t, err)
cps, err := sut.GetContactPoints(context.Background(), cpsQueryWithName(1, newCp.Name), nil) cps, err := sut.GetContactPoints(context.Background(), cpsQueryWithName(1, newCp.Name), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, cps, 1) require.Len(t, cps, 1)
require.Equal(t, customUID, cps[0].UID) require.Equal(t, customUID, cps[0].UID)
@@ -164,7 +170,7 @@ func TestContactPointService(t *testing.T) {
t.Run("default provenance of contact points is none", func(t *testing.T) { t.Run("default provenance of contact points is none", func(t *testing.T) {
sut := createContactPointServiceSut(t, secretsService) sut := createContactPointServiceSut(t, secretsService)
cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1), nil) cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, models.ProvenanceNone, models.Provenance(cps[0].Provenance)) require.Equal(t, models.ProvenanceNone, models.Provenance(cps[0].Provenance))
@@ -222,7 +228,7 @@ func TestContactPointService(t *testing.T) {
newCp, err := sut.CreateContactPoint(context.Background(), 1, newCp, test.from) newCp, err := sut.CreateContactPoint(context.Background(), 1, newCp, test.from)
require.NoError(t, err) require.NoError(t, err)
cps, err := sut.GetContactPoints(context.Background(), cpsQueryWithName(1, newCp.Name), nil) cps, err := sut.GetContactPoints(context.Background(), cpsQueryWithName(1, newCp.Name), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, newCp.UID, cps[0].UID) require.Equal(t, newCp.UID, cps[0].UID)
require.Equal(t, test.from, models.Provenance(cps[0].Provenance)) require.Equal(t, test.from, models.Provenance(cps[0].Provenance))
@@ -231,7 +237,7 @@ func TestContactPointService(t *testing.T) {
if test.errNil { if test.errNil {
require.NoError(t, err) require.NoError(t, err)
cps, err = sut.GetContactPoints(context.Background(), cpsQueryWithName(1, newCp.Name), nil) cps, err = sut.GetContactPoints(context.Background(), cpsQueryWithName(1, newCp.Name), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, newCp.UID, cps[0].UID) require.Equal(t, newCp.UID, cps[0].UID)
require.Equal(t, test.to, models.Provenance(cps[0].Provenance)) require.Equal(t, test.to, models.Provenance(cps[0].Provenance))
@@ -260,22 +266,23 @@ func TestContactPointService(t *testing.T) {
func TestContactPointServiceDecryptRedact(t *testing.T) { func TestContactPointServiceDecryptRedact(t *testing.T) {
secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(db.InitTestDB(t))) secretsService := manager.SetupTestService(t, database.ProvideSecretsStore(db.InitTestDB(t)))
receiverServiceWithAC := func(ecp *ContactPointService) *notifier.ReceiverService {
return notifier.NewReceiverService( redactedUser := &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()), 1: {
// Get won't use the sut's config store, so we can use a different one here. accesscontrol.ActionAlertingProvisioningRead: nil,
fakes.NewFakeAlertmanagerConfigStore(createEncryptedConfig(t, secretsService)), },
ecp.provenanceStore, }}
ecp.encryptionService,
ecp.xact, decryptedUser := &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{
log.NewNopLogger(), 1: {
) accesscontrol.ActionAlertingProvisioningReadSecrets: nil,
} },
}}
t.Run("GetContactPoints gets redacted contact points by default", func(t *testing.T) { t.Run("GetContactPoints gets redacted contact points by default", func(t *testing.T) {
sut := createContactPointServiceSut(t, secretsService) sut := createContactPointServiceSut(t, secretsService)
cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1), nil) cps, err := sut.GetContactPoints(context.Background(), cpsQuery(1), redactedUser)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, cps, 2) require.Len(t, cps, 2)
@@ -285,16 +292,14 @@ func TestContactPointServiceDecryptRedact(t *testing.T) {
t.Run("GetContactPoints errors when Decrypt = true and user does not have permissions", func(t *testing.T) { t.Run("GetContactPoints errors when Decrypt = true and user does not have permissions", func(t *testing.T) {
sut := createContactPointServiceSut(t, secretsService) sut := createContactPointServiceSut(t, secretsService)
sut.receiverService = receiverServiceWithAC(sut)
q := cpsQuery(1) q := cpsQuery(1)
q.Decrypt = true q.Decrypt = true
_, err := sut.GetContactPoints(context.Background(), q, nil) _, err := sut.GetContactPoints(context.Background(), q, redactedUser)
require.ErrorIs(t, err, ErrPermissionDenied) require.ErrorIs(t, err, ErrPermissionDenied)
}) })
t.Run("GetContactPoints errors when Decrypt = true and user is nil", func(t *testing.T) { t.Run("GetContactPoints errors when Decrypt = true and user is nil", func(t *testing.T) {
sut := createContactPointServiceSut(t, secretsService) sut := createContactPointServiceSut(t, secretsService)
sut.receiverService = receiverServiceWithAC(sut)
q := cpsQuery(1) q := cpsQuery(1)
q.Decrypt = true q.Decrypt = true
@@ -304,16 +309,11 @@ func TestContactPointServiceDecryptRedact(t *testing.T) {
t.Run("GetContactPoints gets decrypted contact points when Decrypt = true and user has permissions", func(t *testing.T) { t.Run("GetContactPoints gets decrypted contact points when Decrypt = true and user has permissions", func(t *testing.T) {
sut := createContactPointServiceSut(t, secretsService) sut := createContactPointServiceSut(t, secretsService)
sut.receiverService = receiverServiceWithAC(sut)
expectedName := "slack receiver" expectedName := "slack receiver"
q := cpsQueryWithName(1, expectedName) q := cpsQueryWithName(1, expectedName)
q.Decrypt = true q.Decrypt = true
cps, err := sut.GetContactPoints(context.Background(), q, &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{ cps, err := sut.GetContactPoints(context.Background(), q, decryptedUser)
1: {
accesscontrol.ActionAlertingProvisioningReadSecrets: nil,
},
}})
require.NoError(t, err) require.NoError(t, err)
require.Len(t, cps, 1) require.Len(t, cps, 1)
@@ -361,7 +361,7 @@ func createContactPointServiceSut(t *testing.T, secretService secrets.Service) *
provisioningStore := fakes.NewFakeProvisioningStore() provisioningStore := fakes.NewFakeProvisioningStore()
receiverService := notifier.NewReceiverService( receiverService := notifier.NewReceiverService(
actest.FakeAccessControl{}, acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()),
store, store,
provisioningStore, provisioningStore,
secretService, secretService,

View File

@@ -37,7 +37,7 @@ func (c *defaultContactPointProvisioner) Provision(ctx context.Context,
if _, exists := cpsCache[contactPointsConfig.OrgID]; !exists { if _, exists := cpsCache[contactPointsConfig.OrgID]; !exists {
cps, err := c.contactPointService.GetContactPoints(ctx, provisioning.ContactPointQuery{ cps, err := c.contactPointService.GetContactPoints(ctx, provisioning.ContactPointQuery{
OrgID: contactPointsConfig.OrgID, OrgID: contactPointsConfig.OrgID,
}, nil) }, provisionerUser(contactPointsConfig.OrgID))
if err != nil { if err != nil {
return err return err
} }