From 4abd88ec95d33648876025434bffab339c657d36 Mon Sep 17 00:00:00 2001 From: Yuri Tseretyan Date: Wed, 22 Oct 2025 13:01:26 -0400 Subject: [PATCH] refactor: consolidate all encrypt\decrypt functions --- pkg/services/ngalert/notifier/crypto.go | 26 +++++++++++++++ pkg/services/ngalert/notifier/receiver_svc.go | 21 ++---------- pkg/services/ngalert/remote/alertmanager.go | 19 ++--------- .../ngalert/remote/alertmanager_test.go | 33 +++---------------- 4 files changed, 35 insertions(+), 64 deletions(-) diff --git a/pkg/services/ngalert/notifier/crypto.go b/pkg/services/ngalert/notifier/crypto.go index 246cd03d64d..04a651a174f 100644 --- a/pkg/services/ngalert/notifier/crypto.go +++ b/pkg/services/ngalert/notifier/crypto.go @@ -378,3 +378,29 @@ func EncryptedReceivers(receivers []*definitions.PostableApiReceiver, encryptFn } return encrypted, nil } + +// DecryptIntegrationSettings returns a function to decrypt integration settings. +func DecryptIntegrationSettings(ctx context.Context, ss secretService) models.DecryptFn { + return func(value string) (string, error) { + decoded, err := base64.StdEncoding.DecodeString(value) + if err != nil { + return "", err + } + decrypted, err := ss.Decrypt(ctx, decoded) + if err != nil { + return "", err + } + return string(decrypted), nil + } +} + +// EncryptIntegrationSettings returns a function to encrypt integration settings. +func EncryptIntegrationSettings(ctx context.Context, ss secretService) models.EncryptFn { + return func(payload string) (string, error) { + encrypted, err := ss.Encrypt(ctx, []byte(payload), secrets.WithoutScope()) + if err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(encrypted), nil + } +} diff --git a/pkg/services/ngalert/notifier/receiver_svc.go b/pkg/services/ngalert/notifier/receiver_svc.go index 0997ee3bbca..75de117e9af 100644 --- a/pkg/services/ngalert/notifier/receiver_svc.go +++ b/pkg/services/ngalert/notifier/receiver_svc.go @@ -2,7 +2,6 @@ package notifier import ( "context" - "encoding/base64" "errors" "fmt" "strings" @@ -684,28 +683,12 @@ func (rs *ReceiverService) deleteProvenances(ctx context.Context, orgID int64, i // decryptor returns a models.DecryptFn that decrypts a secure setting. If decryption fails, the fallback value is used. func (rs *ReceiverService) decryptor(ctx context.Context) models.DecryptFn { - return func(value string) (string, error) { - decoded, err := base64.StdEncoding.DecodeString(value) - if err != nil { - return "", err - } - decrypted, err := rs.encryptionService.Decrypt(ctx, decoded) - if err != nil { - return "", err - } - return string(decrypted), nil - } + return DecryptIntegrationSettings(ctx, rs.encryptionService) } // encryptor creates an encrypt function that delegates to secrets.Service and returns the base64 encoded result. func (rs *ReceiverService) encryptor(ctx context.Context) models.EncryptFn { - return func(payload string) (string, error) { - s, err := rs.encryptionService.Encrypt(ctx, []byte(payload), secrets.WithoutScope()) - if err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(s), nil - } + return EncryptIntegrationSettings(ctx, rs.encryptionService) } // checkOptimisticConcurrency checks if the existing receiver's version matches the desired version. diff --git a/pkg/services/ngalert/remote/alertmanager.go b/pkg/services/ngalert/remote/alertmanager.go index a7c99f8518c..d0cb69b51b4 100644 --- a/pkg/services/ngalert/remote/alertmanager.go +++ b/pkg/services/ngalert/remote/alertmanager.go @@ -57,6 +57,7 @@ func NoopAutogenFn(_ context.Context, _ log.Logger, _ int64, _ *apimodels.Postab } type Crypto interface { + Encrypt(ctx context.Context, payload []byte, opt secrets.EncryptionOptions) ([]byte, error) Decrypt(ctx context.Context, payload []byte) ([]byte, error) DecryptExtraConfigs(ctx context.Context, config *apimodels.PostableUserConfig) error } @@ -289,20 +290,6 @@ func (am *Alertmanager) isDefaultConfiguration(configHash string) bool { return configHash == am.defaultConfigHash } -func decrypter(ctx context.Context, crypto Crypto) models.DecryptFn { - return func(value string) (string, error) { - decoded, err := base64.StdEncoding.DecodeString(value) - if err != nil { - return "", err - } - decrypted, err := crypto.Decrypt(ctx, decoded) - if err != nil { - return "", err - } - return string(decrypted), nil - } -} - // buildConfiguration takes a raw Alertmanager configuration and returns a config that the remote Alertmanager can use. // It parses the initial configuration, adds auto-generated routes, decrypts receivers, and merges the extra configs. func (am *Alertmanager) buildConfiguration(ctx context.Context, raw []byte, createdAtEpoch int64, autogenInvalidReceiverAction notifier.InvalidReceiversAction) (remoteClient.UserGrafanaConfig, error) { @@ -317,7 +304,7 @@ func (am *Alertmanager) buildConfiguration(ctx context.Context, raw []byte, crea } // Decrypt the receivers in the configuration. - decryptedReceivers, err := notifier.DecryptedReceivers(c.AlertmanagerConfig.Receivers, decrypter(ctx, am.crypto)) + decryptedReceivers, err := notifier.DecryptedReceivers(c.AlertmanagerConfig.Receivers, notifier.DecryptIntegrationSettings(ctx, am.crypto)) if err != nil { return remoteClient.UserGrafanaConfig{}, fmt.Errorf("unable to decrypt receivers: %w", err) } @@ -619,7 +606,7 @@ func (am *Alertmanager) GetReceivers(ctx context.Context) ([]apimodels.Receiver, } func (am *Alertmanager) TestReceivers(ctx context.Context, c apimodels.TestReceiversConfigBodyParams) (*alertingNotify.TestReceiversResult, int, error) { - decryptedReceivers, err := notifier.DecryptedReceivers(c.Receivers, decrypter(ctx, am.crypto)) + decryptedReceivers, err := notifier.DecryptedReceivers(c.Receivers, notifier.DecryptIntegrationSettings(ctx, am.crypto)) if err != nil { return nil, 0, fmt.Errorf("failed to decrypt receivers: %w", err) } diff --git a/pkg/services/ngalert/remote/alertmanager_test.go b/pkg/services/ngalert/remote/alertmanager_test.go index d6f66756454..1a1d3943324 100644 --- a/pkg/services/ngalert/remote/alertmanager_test.go +++ b/pkg/services/ngalert/remote/alertmanager_test.go @@ -43,7 +43,6 @@ import ( "github.com/grafana/grafana/pkg/services/ngalert/notifier" "github.com/grafana/grafana/pkg/services/ngalert/remote/client" ngfakes "github.com/grafana/grafana/pkg/services/ngalert/tests/fakes" - "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets/database" "github.com/grafana/grafana/pkg/services/secrets/fakes" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" @@ -298,13 +297,7 @@ func TestIntegrationApplyConfig(t *testing.T) { var c apimodels.PostableUserConfig require.NoError(t, json.Unmarshal([]byte(testGrafanaConfigWithSecret), &c)) secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(db.InitTestDB(t))) - encryptedReceivers, err := notifier.EncryptedReceivers(c.AlertmanagerConfig.Receivers, func(payload string) (string, error) { - encrypted, err := secretsService.Encrypt(context.Background(), []byte(payload), secrets.WithoutScope()) - if err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(encrypted), nil - }) + encryptedReceivers, err := notifier.EncryptedReceivers(c.AlertmanagerConfig.Receivers, notifier.EncryptIntegrationSettings(context.Background(), secretsService)) c.AlertmanagerConfig.Receivers = encryptedReceivers require.NoError(t, err) @@ -462,13 +455,7 @@ func TestCompareAndSendConfiguration(t *testing.T) { // Create a config with correctly encrypted and encoded secrets. var inputCfg apimodels.PostableUserConfig require.NoError(t, json.Unmarshal([]byte(testGrafanaConfigWithSecret), &inputCfg)) - encryptedReceivers, err := notifier.EncryptedReceivers(inputCfg.AlertmanagerConfig.Receivers, func(payload string) (string, error) { - encrypted, err := secretsService.Encrypt(context.Background(), []byte(payload), secrets.WithoutScope()) - if err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(encrypted), nil - }) + encryptedReceivers, err := notifier.EncryptedReceivers(inputCfg.AlertmanagerConfig.Receivers, notifier.EncryptIntegrationSettings(context.Background(), secretsService)) inputCfg.AlertmanagerConfig.Receivers = encryptedReceivers require.NoError(t, err) testGrafanaConfigWithEncryptedSecret, err := json.Marshal(inputCfg) @@ -663,13 +650,7 @@ func Test_TestReceiversDecryptsSecureSettings(t *testing.T) { var inputCfg apimodels.PostableUserConfig require.NoError(t, json.Unmarshal([]byte(testGrafanaConfigWithSecret), &inputCfg)) - encryptedReceivers, err := notifier.EncryptedReceivers(inputCfg.AlertmanagerConfig.Receivers, func(payload string) (string, error) { - encrypted, err := secretsService.Encrypt(context.Background(), []byte(payload), secrets.WithoutScope()) - if err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(encrypted), nil - }) + encryptedReceivers, err := notifier.EncryptedReceivers(inputCfg.AlertmanagerConfig.Receivers, notifier.EncryptIntegrationSettings(context.Background(), secretsService)) inputCfg.AlertmanagerConfig.Receivers = encryptedReceivers require.NoError(t, err) @@ -1037,13 +1018,7 @@ func TestIntegrationRemoteAlertmanagerConfiguration(t *testing.T) { { postableCfg, err := notifier.Load([]byte(testGrafanaConfigWithSecret)) require.NoError(t, err) - encryptedReceivers, err := notifier.EncryptedReceivers(postableCfg.AlertmanagerConfig.Receivers, func(payload string) (string, error) { - encrypted, err := secretsService.Encrypt(context.Background(), []byte(payload), secrets.WithoutScope()) - if err != nil { - return "", err - } - return base64.StdEncoding.EncodeToString(encrypted), nil - }) + encryptedReceivers, err := notifier.EncryptedReceivers(postableCfg.AlertmanagerConfig.Receivers, notifier.EncryptIntegrationSettings(context.Background(), secretsService)) postableCfg.AlertmanagerConfig.Receivers = encryptedReceivers require.NoError(t, err)