Encryption: Refactor securejsondata.SecureJsonData to stop relying on global functions (#38865)

* Encryption: Add support to encrypt/decrypt sjd

* Add datasources.Service as a proxy to datasources db operations

* Encrypt ds.SecureJsonData before calling SQLStore

* Move ds cache code into ds service

* Fix tlsmanager tests

* Fix pluginproxy tests

* Remove some securejsondata.GetEncryptedJsonData usages

* Add pluginsettings.Service as a proxy for plugin settings db operations

* Add AlertNotificationService as a proxy for alert notification db operations

* Remove some securejsondata.GetEncryptedJsonData usages

* Remove more securejsondata.GetEncryptedJsonData usages

* Fix lint errors

* Minor fixes

* Remove encryption global functions usages from ngalert

* Fix lint errors

* Minor fixes

* Minor fixes

* Remove securejsondata.DecryptedValue usage

* Refactor the refactor

* Remove securejsondata.DecryptedValue usage

* Move securejsondata to migrations package

* Move securejsondata to migrations package

* Minor fix

* Fix integration test

* Fix integration tests

* Undo undesired changes

* Fix tests

* Add context.Context into encryption methods

* Fix tests

* Fix tests

* Fix tests

* Trigger CI

* Fix test

* Add names to params of encryption service interface

* Remove bus from CacheServiceImpl

* Add logging

* Add keys to logger

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>

* Add missing key to logger

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>

* Undo changes in markdown files

* Fix formatting

* Add context to secrets service

* Rename decryptSecureJsonData to decryptSecureJsonDataFn

* Name args in GetDecryptedValueFn

* Add template back to NewAlertmanagerNotifier

* Copy GetDecryptedValueFn to ngalert

* Add logging to pluginsettings

* Fix pluginsettings test

Co-authored-by: Tania B <yalyna.ts@gmail.com>
Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
This commit is contained in:
Joan López de la Franca Beltran
2021-10-07 17:33:50 +03:00
committed by GitHub
co-authored by Emil Tullstedt Tania B
parent da813877fb
commit 722c414fef
141 changed files with 1968 additions and 1197 deletions
+4 -2
View File
@@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/encryption"
"github.com/grafana/grafana/pkg/services/rendering"
"github.com/grafana/grafana/pkg/setting"
"github.com/opentracing/opentracing-go"
@@ -47,7 +48,8 @@ func (e *AlertEngine) IsDisabled() bool {
// ProvideAlertEngine returns a new AlertEngine.
func ProvideAlertEngine(renderer rendering.Service, bus bus.Bus, requestValidator models.PluginRequestValidator,
dataService plugins.DataRequestHandler, usageStatsService usagestats.Service, cfg *setting.Cfg) *AlertEngine {
dataService plugins.DataRequestHandler, usageStatsService usagestats.Service, encryptionService encryption.Service,
cfg *setting.Cfg) *AlertEngine {
e := &AlertEngine{
Cfg: cfg,
RenderService: renderer,
@@ -62,7 +64,7 @@ func ProvideAlertEngine(renderer rendering.Service, bus bus.Bus, requestValidato
e.evalHandler = NewEvalHandler(e.DataService)
e.ruleReader = newRuleReader()
e.log = log.New("alerting.engine")
e.resultHandler = newResultHandler(e.RenderService)
e.resultHandler = newResultHandler(e.RenderService, encryptionService.GetDecryptedValue)
e.registerUsageMetrics()
@@ -13,7 +13,7 @@ import (
"time"
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/setting"
. "github.com/smartystreets/goconvey/convey"
)
@@ -21,7 +21,7 @@ import (
func TestEngineTimeouts(t *testing.T) {
Convey("Alerting engine timeout tests", t, func() {
usMock := &usagestats.UsageStatsMock{T: t}
engine := ProvideAlertEngine(nil, nil, nil, nil, usMock, setting.NewCfg())
engine := ProvideAlertEngine(nil, nil, nil, nil, usMock, ossencryption.ProvideService(), setting.NewCfg())
setting.AlertingNotificationTimeout = 30 * time.Second
setting.AlertingMaxAttempts = 3
engine.resultHandler = &FakeResultHandler{}
+2 -1
View File
@@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/setting"
. "github.com/smartystreets/goconvey/convey"
)
@@ -44,7 +45,7 @@ func TestEngineProcessJob(t *testing.T) {
Convey("Alerting engine job processing", t, func() {
bus := bus.New()
usMock := &usagestats.UsageStatsMock{T: t}
engine := ProvideAlertEngine(nil, bus, nil, nil, usMock, setting.NewCfg())
engine := ProvideAlertEngine(nil, bus, nil, nil, usMock, ossencryption.ProvideService(), setting.NewCfg())
setting.AlertingEvaluationTimeout = 30 * time.Second
setting.AlertingNotificationTimeout = 30 * time.Second
setting.AlertingMaxAttempts = 3
+5 -3
View File
@@ -181,12 +181,14 @@ func TestAlertRuleExtraction(t *testing.T) {
})
t.Run("Alert notifications are in DB", func(t *testing.T) {
sqlstore.InitTestDB(t)
sqlStore := sqlstore.InitTestDB(t)
firstNotification := models.CreateAlertNotificationCommand{Uid: "notifier1", OrgId: 1, Name: "1"}
err = sqlstore.CreateAlertNotificationCommand(&firstNotification)
err = sqlStore.CreateAlertNotificationCommand(&firstNotification)
require.Nil(t, err)
secondNotification := models.CreateAlertNotificationCommand{Uid: "notifier2", OrgId: 1, Name: "2"}
err = sqlstore.CreateAlertNotificationCommand(&secondNotification)
err = sqlStore.CreateAlertNotificationCommand(&secondNotification)
require.Nil(t, err)
json, err := ioutil.ReadFile("./testdata/influxdb-alert.json")
+11 -5
View File
@@ -83,16 +83,18 @@ type ShowWhen struct {
Is string `json:"is"`
}
func newNotificationService(renderService rendering.Service) *notificationService {
func newNotificationService(renderService rendering.Service, decryptFn GetDecryptedValueFn) *notificationService {
return &notificationService{
log: log.New("alerting.notifier"),
renderService: renderService,
decryptFn: decryptFn,
}
}
type notificationService struct {
log log.Logger
renderService rendering.Service
decryptFn GetDecryptedValueFn
}
func (n *notificationService) SendIfNeeded(evalCtx *EvalContext) error {
@@ -250,7 +252,7 @@ func (n *notificationService) getNeededNotifiers(orgID int64, notificationUids [
var result notifierStateSlice
for _, notification := range query.Result {
not, err := InitNotifier(notification)
not, err := InitNotifier(notification, n.decryptFn)
if err != nil {
n.log.Error("Could not create notifier", "notifier", notification.Uid, "error", err)
continue
@@ -280,17 +282,21 @@ func (n *notificationService) getNeededNotifiers(orgID int64, notificationUids [
}
// InitNotifier instantiate a new notifier based on the model.
func InitNotifier(model *models.AlertNotification) (Notifier, error) {
func InitNotifier(model *models.AlertNotification, fn GetDecryptedValueFn) (Notifier, error) {
notifierPlugin, found := notifierFactories[model.Type]
if !found {
return nil, fmt.Errorf("unsupported notification type %q", model.Type)
}
return notifierPlugin.Factory(model)
return notifierPlugin.Factory(model, fn)
}
// GetDecryptedValueFn is a function that returns the decrypted value of
// the given key. If the key is not present, then it returns the fallback value.
type GetDecryptedValueFn func(ctx context.Context, sjd map[string][]byte, key string, fallback string, secret string) string
// NotifierFactory is a signature for creating notifiers.
type NotifierFactory func(notification *models.AlertNotification) (Notifier, error)
type NotifierFactory func(*models.AlertNotification, GetDecryptedValueFn) (Notifier, error)
var notifierFactories = make(map[string]*NotifierPlugin)
+2 -2
View File
@@ -263,7 +263,7 @@ func notificationServiceScenario(t *testing.T, name string, evalCtx *EvalContext
},
}
scenarioCtx.notificationService = newNotificationService(renderService)
scenarioCtx.notificationService = newNotificationService(renderService, nil)
fn(scenarioCtx)
})
}
@@ -279,7 +279,7 @@ type testNotifier struct {
Frequency time.Duration
}
func newTestNotifier(model *models.AlertNotification) (Notifier, error) {
func newTestNotifier(model *models.AlertNotification, _ GetDecryptedValueFn) (Notifier, error) {
uploadImage := true
value, exist := model.Settings.CheckGet("uploadImage")
if exist {
@@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
func init() {
@@ -49,7 +50,7 @@ func init() {
}
// NewAlertmanagerNotifier returns a new Alertmanager notifier
func NewAlertmanagerNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewAlertmanagerNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
urlString := model.Settings.Get("url").MustString()
if urlString == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -63,7 +64,7 @@ func NewAlertmanagerNotifier(model *models.AlertNotification) (alerting.Notifier
}
}
basicAuthUser := model.Settings.Get("basicAuthUser").MustString()
basicAuthPassword := model.DecryptedValue("basicAuthPassword", model.Settings.Get("basicAuthPassword").MustString())
basicAuthPassword := fn(context.Background(), model.SecureSettings, "basicAuthPassword", model.Settings.Get("basicAuthPassword").MustString(), setting.SecretKey)
return &AlertmanagerNotifier{
NotifierBase: NewNotifierBase(model),
@@ -4,15 +4,14 @@ import (
"context"
"testing"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/stretchr/testify/assert"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/validations"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/assert"
)
func TestReplaceIllegalCharswithUnderscore(t *testing.T) {
@@ -93,7 +92,7 @@ func TestAlertmanagerNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewAlertmanagerNotifier(model)
_, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -107,7 +106,7 @@ func TestAlertmanagerNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewAlertmanagerNotifier(model)
not, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
alertmanagerNotifier := not.(*AlertmanagerNotifier)
So(err, ShouldBeNil)
@@ -126,7 +125,7 @@ func TestAlertmanagerNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewAlertmanagerNotifier(model)
not, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
alertmanagerNotifier := not.(*AlertmanagerNotifier)
So(err, ShouldBeNil)
+2 -4
View File
@@ -5,14 +5,12 @@ import (
"testing"
"time"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/stretchr/testify/assert"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/validations"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/assert"
)
func TestShouldSendAlertNotification(t *testing.T) {
+1 -1
View File
@@ -47,7 +47,7 @@ func init() {
})
}
func newDingDingNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func newDingDingNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -4,11 +4,11 @@ import (
"context"
"testing"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/validations"
. "github.com/smartystreets/goconvey/convey"
)
@@ -24,7 +24,7 @@ func TestDingDingNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := newDingDingNotifier(model)
_, err := newDingDingNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
Convey("settings should trigger incident", func() {
@@ -37,7 +37,7 @@ func TestDingDingNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := newDingDingNotifier(model)
not, err := newDingDingNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
notifier := not.(*DingDingNotifier)
So(err, ShouldBeNil)
+1 -1
View File
@@ -51,7 +51,7 @@ func init() {
})
}
func newDiscordNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func newDiscordNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
avatar := model.Settings.Get("avatar_url").MustString()
content := model.Settings.Get("content").MustString()
url := model.Settings.Get("url").MustString()
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
. "github.com/smartystreets/goconvey/convey"
)
@@ -21,7 +22,7 @@ func TestDiscordNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := newDiscordNotifier(model)
_, err := newDiscordNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -40,7 +41,7 @@ func TestDiscordNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := newDiscordNotifier(model)
not, err := newDiscordNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
discordNotifier := not.(*DiscordNotifier)
So(err, ShouldBeNil)
+1 -1
View File
@@ -48,7 +48,7 @@ type EmailNotifier struct {
// NewEmailNotifier is the constructor function
// for the EmailNotifier.
func NewEmailNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewEmailNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
addressesString := model.Settings.Get("addresses").MustString()
singleEmail := model.Settings.Get("singleEmail").MustBool(false)
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
. "github.com/smartystreets/goconvey/convey"
)
@@ -21,7 +22,7 @@ func TestEmailNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewEmailNotifier(model)
_, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -38,7 +39,7 @@ func TestEmailNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewEmailNotifier(model)
not, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
emailNotifier := not.(*EmailNotifier)
So(err, ShouldBeNil)
@@ -62,7 +63,7 @@ func TestEmailNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewEmailNotifier(model)
not, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
emailNotifier := not.(*EmailNotifier)
So(err, ShouldBeNil)
@@ -32,7 +32,7 @@ func init() {
})
}
func newGoogleChatNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func newGoogleChatNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
. "github.com/smartystreets/goconvey/convey"
)
@@ -21,7 +22,7 @@ func TestGoogleChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := newGoogleChatNotifier(model)
_, err := newGoogleChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -38,7 +39,7 @@ func TestGoogleChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := newGoogleChatNotifier(model)
not, err := newGoogleChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
webhookNotifier := not.(*GoogleChatNotifier)
So(err, ShouldBeNil)
+1 -1
View File
@@ -53,7 +53,7 @@ const (
// NewHipChatNotifier is the constructor functions
// for the HipChatNotifier
func NewHipChatNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewHipChatNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if strings.HasSuffix(url, "/") {
url = url[:len(url)-1]
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
. "github.com/smartystreets/goconvey/convey"
)
@@ -22,7 +23,7 @@ func TestHipChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewHipChatNotifier(model)
_, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -38,7 +39,7 @@ func TestHipChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewHipChatNotifier(model)
not, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
hipchatNotifier := not.(*HipChatNotifier)
So(err, ShouldBeNil)
@@ -64,7 +65,7 @@ func TestHipChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewHipChatNotifier(model)
not, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
hipchatNotifier := not.(*HipChatNotifier)
So(err, ShouldBeNil)
+1 -1
View File
@@ -41,7 +41,7 @@ func init() {
}
// NewKafkaNotifier is the constructor function for the Kafka notifier.
func NewKafkaNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewKafkaNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
endpoint := model.Settings.Get("kafkaRestProxy").MustString()
if endpoint == "" {
return nil, alerting.ValidationError{Reason: "Could not find kafka rest proxy endpoint property in settings"}
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
. "github.com/smartystreets/goconvey/convey"
)
@@ -21,7 +22,7 @@ func TestKafkaNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewKafkaNotifier(model)
_, err := NewKafkaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -39,7 +40,7 @@ func TestKafkaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewKafkaNotifier(model)
not, err := NewKafkaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
kafkaNotifier := not.(*KafkaNotifier)
So(err, ShouldBeNil)
+4 -2
View File
@@ -1,6 +1,7 @@
package notifiers
import (
"context"
"fmt"
"net/url"
@@ -8,6 +9,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
func init() {
@@ -35,8 +37,8 @@ const (
)
// NewLINENotifier is the constructor for the LINE notifier
func NewLINENotifier(model *models.AlertNotification) (alerting.Notifier, error) {
token := model.DecryptedValue("token", model.Settings.Get("token").MustString())
func NewLINENotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
token := fn(context.Background(), model.SecureSettings, "token", model.Settings.Get("token").MustString(), setting.SecretKey)
if token == "" {
return nil, alerting.ValidationError{Reason: "Could not find token in settings"}
}
+3 -2
View File
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
. "github.com/smartystreets/goconvey/convey"
)
@@ -20,7 +21,7 @@ func TestLineNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewLINENotifier(model)
_, err := NewLINENotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
Convey("settings should trigger incident", func() {
@@ -35,7 +36,7 @@ func TestLineNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewLINENotifier(model)
not, err := NewLINENotifier(model, ossencryption.ProvideService().GetDecryptedValue)
lineNotifier := not.(*LineNotifier)
So(err, ShouldBeNil)
+4 -2
View File
@@ -1,6 +1,7 @@
package notifiers
import (
"context"
"fmt"
"strconv"
@@ -9,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
const (
@@ -82,10 +84,10 @@ const (
)
// NewOpsGenieNotifier is the constructor for OpsGenie.
func NewOpsGenieNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewOpsGenieNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
autoClose := model.Settings.Get("autoClose").MustBool(true)
overridePriority := model.Settings.Get("overridePriority").MustBool(true)
apiKey := model.DecryptedValue("apiKey", model.Settings.Get("apiKey").MustString())
apiKey := fn(context.Background(), model.SecureSettings, "apiKey", model.Settings.Get("apiKey").MustString(), setting.SecretKey)
apiURL := model.Settings.Get("apiUrl").MustString()
if apiKey == "" {
return nil, alerting.ValidationError{Reason: "Could not find api key property in settings"}
@@ -4,12 +4,12 @@ import (
"context"
"testing"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/validations"
. "github.com/smartystreets/goconvey/convey"
)
@@ -26,7 +26,7 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewOpsGenieNotifier(model)
_, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -43,7 +43,7 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewOpsGenieNotifier(model)
not, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
opsgenieNotifier := not.(*OpsGenieNotifier)
So(err, ShouldBeNil)
@@ -67,7 +67,7 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewOpsGenieNotifier(model)
_, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
So(err, ShouldHaveSameTypeAs, alerting.ValidationError{})
So(err.Error(), ShouldEndWith, "Invalid value for sendTagsAs: \"not_a_valid_value\"")
@@ -90,7 +90,7 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
notifier, notifierErr := NewOpsGenieNotifier(model) // unhandled error
notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue) // unhandled error
opsgenieNotifier := notifier.(*OpsGenieNotifier)
@@ -140,7 +140,7 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
notifier, notifierErr := NewOpsGenieNotifier(model) // unhandled error
notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue) // unhandled error
opsgenieNotifier := notifier.(*OpsGenieNotifier)
@@ -190,7 +190,7 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
notifier, notifierErr := NewOpsGenieNotifier(model) // unhandled error
notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue) // unhandled error
opsgenieNotifier := notifier.(*OpsGenieNotifier)
+4 -2
View File
@@ -1,6 +1,7 @@
package notifiers
import (
"context"
"os"
"strconv"
"strings"
@@ -11,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
func init() {
@@ -74,10 +76,10 @@ var (
)
// NewPagerdutyNotifier is the constructor for the PagerDuty notifier
func NewPagerdutyNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewPagerdutyNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
severity := model.Settings.Get("severity").MustString("critical")
autoResolve := model.Settings.Get("autoResolve").MustBool(false)
key := model.DecryptedValue("integrationKey", model.Settings.Get("integrationKey").MustString())
key := fn(context.Background(), model.SecureSettings, "integrationKey", model.Settings.Get("integrationKey").MustString(), setting.SecretKey)
messageInDetails := model.Settings.Get("messageInDetails").MustBool(false)
if key == "" {
return nil, alerting.ValidationError{Reason: "Could not find integration key property in settings"}
@@ -5,13 +5,13 @@ import (
"strings"
"testing"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/google/go-cmp/cmp"
"github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/validations"
. "github.com/smartystreets/goconvey/convey"
)
@@ -40,7 +40,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewPagerdutyNotifier(model)
_, err = NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -56,7 +56,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
pagerdutyNotifier := not.(*PagerdutyNotifier)
So(err, ShouldBeNil)
@@ -79,7 +79,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
pagerdutyNotifier := not.(*PagerdutyNotifier)
So(err, ShouldBeNil)
@@ -106,7 +106,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
pagerdutyNotifier := not.(*PagerdutyNotifier)
So(err, ShouldBeNil)
@@ -131,7 +131,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldBeNil)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@@ -188,7 +188,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldBeNil)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@@ -245,7 +245,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldBeNil)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@@ -315,7 +315,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldBeNil)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@@ -395,7 +395,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldBeNil)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@@ -474,7 +474,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldBeNil)
pagerdutyNotifier := not.(*PagerdutyNotifier)
+6 -3
View File
@@ -2,12 +2,15 @@ package notifiers
import (
"bytes"
"context"
"fmt"
"io"
"mime/multipart"
"os"
"strconv"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
@@ -191,9 +194,9 @@ func init() {
}
// NewPushoverNotifier is the constructor for the Pushover Notifier
func NewPushoverNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
userKey := model.DecryptedValue("userKey", model.Settings.Get("userKey").MustString())
APIToken := model.DecryptedValue("apiToken", model.Settings.Get("apiToken").MustString())
func NewPushoverNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
userKey := fn(context.Background(), model.SecureSettings, "userKey", model.Settings.Get("userKey").MustString(), setting.SecretKey)
APIToken := fn(context.Background(), model.SecureSettings, "apiToken", model.Settings.Get("apiToken").MustString(), setting.SecretKey)
device := model.Settings.Get("device").MustString()
alertingPriority, err := strconv.Atoi(model.Settings.Get("priority").MustString("0")) // default Normal
if err != nil {
@@ -5,12 +5,11 @@ import (
"strings"
"testing"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/validations"
. "github.com/smartystreets/goconvey/convey"
)
@@ -27,7 +26,7 @@ func TestPushoverNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewPushoverNotifier(model)
_, err := NewPushoverNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -49,7 +48,7 @@ func TestPushoverNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPushoverNotifier(model)
not, err := NewPushoverNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
pushoverNotifier := not.(*PushoverNotifier)
So(err, ShouldBeNil)
+4 -2
View File
@@ -1,6 +1,7 @@
package notifiers
import (
"context"
"strconv"
"strings"
@@ -9,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
func init() {
@@ -59,7 +61,7 @@ func init() {
}
// NewSensuNotifier is the constructor for the Sensu Notifier.
func NewSensuNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewSensuNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -70,7 +72,7 @@ func NewSensuNotifier(model *models.AlertNotification) (alerting.Notifier, error
URL: url,
User: model.Settings.Get("username").MustString(),
Source: model.Settings.Get("source").MustString(),
Password: model.DecryptedValue("password", model.Settings.Get("password").MustString()),
Password: fn(context.Background(), model.SecureSettings, "password", model.Settings.Get("password").MustString(), setting.SecretKey),
Handler: model.Settings.Get("handler").MustString(),
log: log.New("alerting.notifier.sensu"),
}, nil
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
. "github.com/smartystreets/goconvey/convey"
)
@@ -21,7 +22,7 @@ func TestSensuNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewSensuNotifier(model)
_, err := NewSensuNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -40,7 +41,7 @@ func TestSensuNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSensuNotifier(model)
not, err := NewSensuNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
sensuNotifier := not.(*SensuNotifier)
So(err, ShouldBeNil)
+4 -2
View File
@@ -1,6 +1,7 @@
package notifiers
import (
"context"
"fmt"
"strconv"
"strings"
@@ -11,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
func init() {
@@ -70,9 +72,9 @@ func init() {
}
// NewSensuGoNotifier is the constructor for the Sensu Go Notifier.
func NewSensuGoNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewSensuGoNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
apikey := model.DecryptedValue("apikey", model.Settings.Get("apikey").MustString())
apikey := fn(context.Background(), model.SecureSettings, "apikey", model.Settings.Get("apikey").MustString(), setting.SecretKey)
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find URL property in settings"}
@@ -3,11 +3,11 @@ package notifiers
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSensuGoNotifier(t *testing.T) {
@@ -21,7 +21,7 @@ func TestSensuGoNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewSensuGoNotifier(model)
_, err = NewSensuGoNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
require.Error(t, err)
json = `
@@ -42,7 +42,7 @@ func TestSensuGoNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSensuGoNotifier(model)
not, err := NewSensuGoNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
require.NoError(t, err)
sensuGoNotifier := not.(*SensuGoNotifier)
+3 -3
View File
@@ -124,8 +124,8 @@ var reRecipient *regexp.Regexp = regexp.MustCompile("^((@[a-z0-9][a-zA-Z0-9._-]*
const slackAPIEndpoint = "https://slack.com/api/chat.postMessage"
// NewSlackNotifier is the constructor for the Slack notifier.
func NewSlackNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
urlStr := model.DecryptedValue("url", model.Settings.Get("url").MustString())
func NewSlackNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
urlStr := fn(context.Background(), model.SecureSettings, "url", model.Settings.Get("url").MustString(), setting.SecretKey)
if urlStr == "" {
urlStr = slackAPIEndpoint
}
@@ -150,7 +150,7 @@ func NewSlackNotifier(model *models.AlertNotification) (alerting.Notifier, error
mentionUsersStr := model.Settings.Get("mentionUsers").MustString()
mentionGroupsStr := model.Settings.Get("mentionGroups").MustString()
mentionChannel := model.Settings.Get("mentionChannel").MustString()
token := model.DecryptedValue("token", model.Settings.Get("token").MustString())
token := fn(context.Background(), model.SecureSettings, "token", model.Settings.Get("token").MustString(), setting.SecretKey)
if token == "" && apiURL.String() == slackAPIEndpoint {
return nil, alerting.ValidationError{
Reason: "token must be specified when using the Slack chat API",
+20 -12
View File
@@ -1,11 +1,13 @@
package notifiers
import (
"context"
"testing"
"github.com/grafana/grafana/pkg/components/securejsondata"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -22,7 +24,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewSlackNotifier(model)
_, err = NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
assert.EqualError(t, err, "alert validation error: recipient must be specified when using the Slack chat API")
})
@@ -40,7 +42,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSlackNotifier(model)
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
require.NoError(t, err)
slackNotifier := not.(*SlackNotifier)
assert.Equal(t, "ops", slackNotifier.Name)
@@ -78,7 +80,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSlackNotifier(model)
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
require.NoError(t, err)
slackNotifier := not.(*SlackNotifier)
assert.Equal(t, "ops", slackNotifier.Name)
@@ -110,9 +112,15 @@ func TestSlackNotifier(t *testing.T) {
settingsJSON, err := simplejson.NewJson([]byte(json))
require.NoError(t, err)
securedSettingsJSON := securejsondata.GetEncryptedJsonData(map[string]string{
"token": "xenc-XXXXXXXX-XXXXXXXX-XXXXXXXXXX",
})
encryptionService := ossencryption.ProvideService()
securedSettingsJSON, err := encryptionService.EncryptJsonData(
context.Background(),
map[string]string{
"token": "xenc-XXXXXXXX-XXXXXXXX-XXXXXXXXXX",
}, setting.SecretKey)
require.NoError(t, err)
model := &models.AlertNotification{
Name: "ops",
Type: "slack",
@@ -120,7 +128,7 @@ func TestSlackNotifier(t *testing.T) {
SecureSettings: securedSettingsJSON,
}
not, err := NewSlackNotifier(model)
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
require.NoError(t, err)
slackNotifier := not.(*SlackNotifier)
assert.Equal(t, "ops", slackNotifier.Name)
@@ -151,7 +159,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewSlackNotifier(model)
_, err = NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
assert.EqualError(t, err, "alert validation error: recipient on invalid format: \"#open tsdb\"")
})
@@ -170,7 +178,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewSlackNotifier(model)
_, err = NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
assert.EqualError(t, err, "alert validation error: recipient on invalid format: \"@user name\"")
})
@@ -189,7 +197,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewSlackNotifier(model)
_, err = NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
assert.EqualError(t, err, "alert validation error: recipient on invalid format: \"@User\"")
})
@@ -208,7 +216,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSlackNotifier(model)
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
require.NoError(t, err)
slackNotifier := not.(*SlackNotifier)
assert.Equal(t, "1ABCDE", slackNotifier.recipient)
+1 -1
View File
@@ -30,7 +30,7 @@ func init() {
}
// NewTeamsNotifier is the constructor for Teams notifier.
func NewTeamsNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewTeamsNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
. "github.com/smartystreets/goconvey/convey"
)
@@ -21,7 +22,7 @@ func TestTeamsNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewTeamsNotifier(model)
_, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -38,7 +39,7 @@ func TestTeamsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewTeamsNotifier(model)
not, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
teamsNotifier := not.(*TeamsNotifier)
So(err, ShouldBeNil)
@@ -60,7 +61,7 @@ func TestTeamsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewTeamsNotifier(model)
not, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
teamsNotifier := not.(*TeamsNotifier)
So(err, ShouldBeNil)
+4 -2
View File
@@ -2,6 +2,7 @@ package notifiers
import (
"bytes"
"context"
"fmt"
"io"
"mime/multipart"
@@ -11,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
const (
@@ -61,12 +63,12 @@ type TelegramNotifier struct {
}
// NewTelegramNotifier is the constructor for the Telegram notifier
func NewTelegramNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewTelegramNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
if model.Settings == nil {
return nil, alerting.ValidationError{Reason: "No Settings Supplied"}
}
botToken := model.DecryptedValue("bottoken", model.Settings.Get("bottoken").MustString())
botToken := fn(context.Background(), model.SecureSettings, "bottoken", model.Settings.Get("bottoken").MustString(), setting.SecretKey)
chatID := model.Settings.Get("chatid").MustString()
uploadImage := model.Settings.Get("uploadImage").MustBool()
@@ -4,11 +4,11 @@ import (
"context"
"testing"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/validations"
. "github.com/smartystreets/goconvey/convey"
)
@@ -25,7 +25,7 @@ func TestTelegramNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewTelegramNotifier(model)
_, err := NewTelegramNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -43,7 +43,7 @@ func TestTelegramNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewTelegramNotifier(model)
not, err := NewTelegramNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
telegramNotifier := not.(*TelegramNotifier)
So(err, ShouldBeNil)
+4 -2
View File
@@ -1,6 +1,7 @@
package notifiers
import (
"context"
"fmt"
"net/url"
"strings"
@@ -9,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
var (
@@ -69,14 +71,14 @@ type ThreemaNotifier struct {
}
// NewThreemaNotifier is the constructor for the Threema notifier
func NewThreemaNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewThreemaNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
if model.Settings == nil {
return nil, alerting.ValidationError{Reason: "No Settings Supplied"}
}
gatewayID := model.Settings.Get("gateway_id").MustString()
recipientID := model.Settings.Get("recipient_id").MustString()
apiSecret := model.DecryptedValue("api_secret", model.Settings.Get("api_secret").MustString())
apiSecret := fn(context.Background(), model.SecureSettings, "api_secret", model.Settings.Get("api_secret").MustString(), setting.SecretKey)
// Validation
if gatewayID == "" {
@@ -7,6 +7,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
. "github.com/smartystreets/goconvey/convey"
)
@@ -23,7 +24,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewThreemaNotifier(model)
_, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -42,7 +43,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewThreemaNotifier(model)
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldBeNil)
threemaNotifier := not.(*ThreemaNotifier)
@@ -69,7 +70,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewThreemaNotifier(model)
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(not, ShouldBeNil)
var valErr alerting.ValidationError
So(errors.As(err, &valErr), ShouldBeTrue)
@@ -91,7 +92,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewThreemaNotifier(model)
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(not, ShouldBeNil)
var valErr alerting.ValidationError
So(errors.As(err, &valErr), ShouldBeTrue)
@@ -113,7 +114,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewThreemaNotifier(model)
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(not, ShouldBeNil)
var valErr alerting.ValidationError
So(errors.As(err, &valErr), ShouldBeTrue)
+1 -1
View File
@@ -47,7 +47,7 @@ func init() {
// NewVictoropsNotifier creates an instance of VictoropsNotifier that
// handles posting notifications to Victorops REST API
func NewVictoropsNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewVictoropsNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
autoResolve := model.Settings.Get("autoResolve").MustBool(true)
url := model.Settings.Get("url").MustString()
if url == "" {
@@ -4,12 +4,12 @@ import (
"context"
"testing"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/google/go-cmp/cmp"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/validations"
. "github.com/smartystreets/goconvey/convey"
)
@@ -35,7 +35,7 @@ func TestVictoropsNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewVictoropsNotifier(model)
_, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldNotBeNil)
})
@@ -52,7 +52,7 @@ func TestVictoropsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewVictoropsNotifier(model)
not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
victoropsNotifier := not.(*VictoropsNotifier)
So(err, ShouldBeNil)
@@ -76,7 +76,7 @@ func TestVictoropsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewVictoropsNotifier(model)
not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldBeNil)
victoropsNotifier := not.(*VictoropsNotifier)
@@ -124,7 +124,7 @@ func TestVictoropsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewVictoropsNotifier(model)
not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
So(err, ShouldBeNil)
victoropsNotifier := not.(*VictoropsNotifier)
+4 -2
View File
@@ -1,12 +1,14 @@
package notifiers
import (
"context"
"encoding/json"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/setting"
)
func init() {
@@ -58,13 +60,13 @@ func init() {
// NewWebHookNotifier is the constructor for
// the WebHook notifier.
func NewWebHookNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
func NewWebHookNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
}
password := model.DecryptedValue("password", model.Settings.Get("password").MustString())
password := fn(context.Background(), model.SecureSettings, "password", model.Settings.Get("password").MustString(), setting.SecretKey)
return &WebhookNotifier{
NotifierBase: NewNotifierBase(model),
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -21,7 +22,7 @@ func TestWebhookNotifier_parsingFromSettings(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewWebHookNotifier(model)
_, err = NewWebHookNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
require.Error(t, err)
})
@@ -36,7 +37,7 @@ func TestWebhookNotifier_parsingFromSettings(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewWebHookNotifier(model)
not, err := NewWebHookNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
require.NoError(t, err)
webhookNotifier := not.(*WebhookNotifier)
+2 -2
View File
@@ -24,10 +24,10 @@ type defaultResultHandler struct {
log log.Logger
}
func newResultHandler(renderService rendering.Service) *defaultResultHandler {
func newResultHandler(renderService rendering.Service, decryptFn GetDecryptedValueFn) *defaultResultHandler {
return &defaultResultHandler{
log: log.New("alerting.resultHandler"),
notifier: newNotificationService(renderService),
notifier: newNotificationService(renderService, decryptFn),
}
}
+3 -3
View File
@@ -83,16 +83,16 @@ func TestAlertRuleForParsing(t *testing.T) {
}
func TestAlertRuleModel(t *testing.T) {
sqlstore.InitTestDB(t)
sqlStore := sqlstore.InitTestDB(t)
RegisterCondition("test", func(model *simplejson.Json, index int) (Condition, error) {
return &FakeCondition{}, nil
})
firstNotification := models.CreateAlertNotificationCommand{Uid: "notifier1", OrgId: 1, Name: "1"}
err := sqlstore.CreateAlertNotificationCommand(&firstNotification)
err := sqlStore.CreateAlertNotificationCommand(&firstNotification)
require.Nil(t, err)
secondNotification := models.CreateAlertNotificationCommand{Uid: "notifier2", OrgId: 1, Name: "2"}
err = sqlstore.CreateAlertNotificationCommand(&secondNotification)
err = sqlStore.CreateAlertNotificationCommand(&secondNotification)
require.Nil(t, err)
t.Run("Testing alert rule with notification id and uid", func(t *testing.T) {
+102
View File
@@ -0,0 +1,102 @@
package alerting
import (
"context"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
)
type AlertNotificationService struct {
Bus bus.Bus
SQLStore *sqlstore.SQLStore
EncryptionService encryption.Service
}
func ProvideService(bus bus.Bus, store *sqlstore.SQLStore, encryptionService encryption.Service,
) *AlertNotificationService {
s := &AlertNotificationService{
Bus: bus,
SQLStore: store,
EncryptionService: encryptionService,
}
s.Bus.AddHandler(s.GetAlertNotifications)
s.Bus.AddHandlerCtx(s.CreateAlertNotificationCommand)
s.Bus.AddHandlerCtx(s.UpdateAlertNotification)
s.Bus.AddHandler(s.DeleteAlertNotification)
s.Bus.AddHandler(s.GetAllAlertNotifications)
s.Bus.AddHandlerCtx(s.GetOrCreateAlertNotificationState)
s.Bus.AddHandlerCtx(s.SetAlertNotificationStateToCompleteCommand)
s.Bus.AddHandlerCtx(s.SetAlertNotificationStateToPendingCommand)
s.Bus.AddHandler(s.GetAlertNotificationsWithUid)
s.Bus.AddHandler(s.UpdateAlertNotificationWithUid)
s.Bus.AddHandler(s.DeleteAlertNotificationWithUid)
s.Bus.AddHandler(s.GetAlertNotificationsWithUidToSend)
s.Bus.AddHandlerCtx(s.HandleNotificationTestCommand)
return s
}
func (s *AlertNotificationService) GetAlertNotifications(query *models.GetAlertNotificationsQuery) error {
return s.SQLStore.GetAlertNotifications(query)
}
func (s *AlertNotificationService) CreateAlertNotificationCommand(ctx context.Context, cmd *models.CreateAlertNotificationCommand) error {
var err error
cmd.EncryptedSecureSettings, err = s.EncryptionService.EncryptJsonData(ctx, cmd.SecureSettings, setting.SecretKey)
if err != nil {
return err
}
return s.SQLStore.CreateAlertNotificationCommand(cmd)
}
func (s *AlertNotificationService) UpdateAlertNotification(ctx context.Context, cmd *models.UpdateAlertNotificationCommand) error {
var err error
cmd.EncryptedSecureSettings, err = s.EncryptionService.EncryptJsonData(ctx, cmd.SecureSettings, setting.SecretKey)
if err != nil {
return err
}
return s.SQLStore.UpdateAlertNotification(cmd)
}
func (s *AlertNotificationService) DeleteAlertNotification(cmd *models.DeleteAlertNotificationCommand) error {
return s.SQLStore.DeleteAlertNotification(cmd)
}
func (s *AlertNotificationService) GetAllAlertNotifications(query *models.GetAllAlertNotificationsQuery) error {
return s.SQLStore.GetAllAlertNotifications(query)
}
func (s *AlertNotificationService) GetOrCreateAlertNotificationState(ctx context.Context, cmd *models.GetOrCreateNotificationStateQuery) error {
return s.SQLStore.GetOrCreateAlertNotificationState(ctx, cmd)
}
func (s *AlertNotificationService) SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToCompleteCommand) error {
return s.SQLStore.SetAlertNotificationStateToCompleteCommand(ctx, cmd)
}
func (s *AlertNotificationService) SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToPendingCommand) error {
return s.SQLStore.SetAlertNotificationStateToPendingCommand(ctx, cmd)
}
func (s *AlertNotificationService) GetAlertNotificationsWithUid(query *models.GetAlertNotificationsWithUidQuery) error {
return s.SQLStore.GetAlertNotificationsWithUid(query)
}
func (s *AlertNotificationService) UpdateAlertNotificationWithUid(cmd *models.UpdateAlertNotificationWithUidCommand) error {
return s.SQLStore.UpdateAlertNotificationWithUid(cmd)
}
func (s *AlertNotificationService) DeleteAlertNotificationWithUid(cmd *models.DeleteAlertNotificationWithUidCommand) error {
return s.SQLStore.DeleteAlertNotificationWithUid(cmd)
}
func (s *AlertNotificationService) GetAlertNotificationsWithUidToSend(query *models.GetAlertNotificationsWithUidToSendQuery) error {
return s.SQLStore.GetAlertNotificationsWithUidToSend(query)
}
+56
View File
@@ -0,0 +1,56 @@
package alerting
import (
"context"
"testing"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/require"
)
func TestService(t *testing.T) {
sqlStore := sqlstore.InitTestDB(t)
s := ProvideService(bus.New(), sqlStore, ossencryption.ProvideService())
origSecret := setting.SecretKey
setting.SecretKey = "alert_notification_service_test"
t.Cleanup(func() {
setting.SecretKey = origSecret
})
var an *models.AlertNotification
t.Run("create alert notification should encrypt the secure json data", func(t *testing.T) {
ctx := context.Background()
ss := map[string]string{"password": "12345"}
cmd := models.CreateAlertNotificationCommand{SecureSettings: ss}
err := s.CreateAlertNotificationCommand(ctx, &cmd)
require.NoError(t, err)
an = cmd.Result
decrypted, err := s.EncryptionService.DecryptJsonData(ctx, an.SecureSettings, setting.SecretKey)
require.NoError(t, err)
require.Equal(t, ss, decrypted)
})
t.Run("update alert notification should encrypt the secure json data", func(t *testing.T) {
ctx := context.Background()
ss := map[string]string{"password": "678910"}
cmd := models.UpdateAlertNotificationCommand{Id: an.Id, Settings: simplejson.New(), SecureSettings: ss}
err := s.UpdateAlertNotification(ctx, &cmd)
require.NoError(t, err)
decrypted, err := s.EncryptionService.DecryptJsonData(ctx, cmd.Result.SecureSettings, setting.SecretKey)
require.NoError(t, err)
require.Equal(t, ss, decrypted)
})
}
+14 -12
View File
@@ -6,13 +6,12 @@ import (
"math/rand"
"net/http"
"github.com/grafana/grafana/pkg/components/securejsondata"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
// NotificationTestCommand initiates an test
@@ -31,12 +30,8 @@ var (
logger = log.New("alerting.testnotification")
)
func init() {
bus.AddHandlerCtx("alerting", handleNotificationTestCommand)
}
func handleNotificationTestCommand(ctx context.Context, cmd *NotificationTestCommand) error {
notifier := newNotificationService(nil)
func (s *AlertNotificationService) HandleNotificationTestCommand(ctx context.Context, cmd *NotificationTestCommand) error {
notifier := newNotificationService(nil, nil)
model := &models.AlertNotification{
Name: cmd.Name,
@@ -56,7 +51,11 @@ func handleNotificationTestCommand(ctx context.Context, cmd *NotificationTestCom
}
if query.Result.SecureSettings != nil {
secureSettingsMap = query.Result.SecureSettings.Decrypt()
var err error
secureSettingsMap, err = s.EncryptionService.DecryptJsonData(ctx, query.Result.SecureSettings, setting.SecretKey)
if err != nil {
return err
}
}
}
@@ -64,10 +63,13 @@ func handleNotificationTestCommand(ctx context.Context, cmd *NotificationTestCom
secureSettingsMap[k] = v
}
model.SecureSettings = securejsondata.GetEncryptedJsonData(secureSettingsMap)
notifiers, err := InitNotifier(model)
var err error
model.SecureSettings, err = s.EncryptionService.EncryptJsonData(ctx, secureSettingsMap, setting.SecretKey)
if err != nil {
return err
}
notifiers, err := InitNotifier(model, s.EncryptionService.GetDecryptedValue)
if err != nil {
logger.Error("Failed to create notifier", "error", err.Error())
return err