Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da7be26d34 |
2
go.mod
2
go.mod
@@ -73,7 +73,7 @@ require (
|
||||
github.com/googleapis/gax-go/v2 v2.13.0 // @grafana/grafana-backend-group
|
||||
github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group
|
||||
github.com/gorilla/websocket v1.5.0 // @grafana/grafana-app-platform-squad
|
||||
github.com/grafana/alerting v0.0.0-20241216200650-863916c31666 // @grafana/alerting-backend
|
||||
github.com/grafana/alerting v0.0.0-20250123200557-d08d1a8c6d83 // @grafana/alerting-backend
|
||||
github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 // @grafana/identity-access-team
|
||||
github.com/grafana/authlib/claims v0.0.0-20240827210201-19d5347dd8dd // @grafana/identity-access-team
|
||||
github.com/grafana/codejen v0.0.3 // @grafana/dataviz-squad
|
||||
|
||||
2
go.sum
2
go.sum
@@ -2254,6 +2254,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grafana/alerting v0.0.0-20241216200650-863916c31666 h1:yT+hJkmegtRnpHMYhXbm32D9gqKveXetXd9YFzQy2TI=
|
||||
github.com/grafana/alerting v0.0.0-20241216200650-863916c31666/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU=
|
||||
github.com/grafana/alerting v0.0.0-20250123200557-d08d1a8c6d83 h1:My4siUgC1Fsxw4xIUlUVLOk70W2oHMkV1TyHNzIvXh8=
|
||||
github.com/grafana/alerting v0.0.0-20250123200557-d08d1a8c6d83/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU=
|
||||
github.com/grafana/authlib v0.0.0-20240919120951-58259833c564 h1:zYF/RBulpvMqPYR3gbzJZ8t/j/Eymn5FNidSYkueNCA=
|
||||
github.com/grafana/authlib v0.0.0-20240919120951-58259833c564/go.mod h1:PFzXbCrn0GIpN4KwT6NP1l5Z1CPLfmKHnYx8rZzQcyY=
|
||||
github.com/grafana/authlib/claims v0.0.0-20240827210201-19d5347dd8dd h1:sIlR7n38/MnZvX2qxDEszywXdI5soCwQ78aTDSARvus=
|
||||
|
||||
@@ -267,7 +267,7 @@ type ThreemaIntegration struct {
|
||||
type VictoropsIntegration struct {
|
||||
DisableResolveMessage *bool `json:"-" yaml:"-" hcl:"disable_resolve_message"`
|
||||
|
||||
URL string `json:"url" yaml:"url" hcl:"url"`
|
||||
URL Secret `json:"url" yaml:"url" hcl:"url"`
|
||||
|
||||
MessageType *string `json:"messageType,omitempty" yaml:"messageType,omitempty" hcl:"message_type"`
|
||||
Title *string `json:"title,omitempty" yaml:"title,omitempty" hcl:"title"`
|
||||
|
||||
@@ -388,6 +388,7 @@ func GetAvailableNotifiers() []*NotifierPlugin {
|
||||
Placeholder: "VictorOps url",
|
||||
PropertyName: "url",
|
||||
Required: true,
|
||||
Secure: true,
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Message Type",
|
||||
|
||||
@@ -15,7 +15,7 @@ func TestGetSecretKeysForContactPointType(t *testing.T) {
|
||||
{receiverType: "kafka", expectedSecretFields: []string{"password"}},
|
||||
{receiverType: "email", expectedSecretFields: []string{}},
|
||||
{receiverType: "pagerduty", expectedSecretFields: []string{"integrationKey"}},
|
||||
{receiverType: "victorops", expectedSecretFields: []string{}},
|
||||
{receiverType: "victorops", expectedSecretFields: []string{"url"}},
|
||||
{receiverType: "oncall", expectedSecretFields: []string{"password", "authorization_credentials"}},
|
||||
{receiverType: "pushover", expectedSecretFields: []string{"apiToken", "userKey"}},
|
||||
{receiverType: "slack", expectedSecretFields: []string{"token", "url"}},
|
||||
|
||||
@@ -395,6 +395,14 @@ func (rs *ReceiverService) UpdateReceiver(ctx context.Context, r *models.Receive
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We re-encrypt the existing receiver to ensure any unencrypted secure fields that are correctly encrypted, note this should NOT re-encrypt secure fields that are already encrypted.
|
||||
// This is rare, but can happen if a receiver is created with unencrypted secure fields and then the secure option is added later.
|
||||
// Preferably, this would be handled by receiver config versions and migrations but for now this is a good safety net.
|
||||
err = existing.Encrypt(rs.encryptor(ctx))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check optimistic concurrency.
|
||||
err = rs.checkOptimisticConcurrency(existing, r.Version)
|
||||
if err != nil {
|
||||
|
||||
@@ -583,6 +583,44 @@ func TestReceiverService_Update(t *testing.T) {
|
||||
), rm.Encrypted(models.Base64Enrypt)),
|
||||
expectedProvenances: map[string]models.Provenance{slackIntegration.UID: models.ProvenanceNone},
|
||||
},
|
||||
{
|
||||
name: "encrypts previously unencrypted secure fields",
|
||||
user: writer,
|
||||
receiver: models.CopyReceiverWith(baseReceiver, rm.WithIntegrations(
|
||||
models.CopyIntegrationWith(slackIntegration, im.AddSetting("token", "unencryptedValue"))),
|
||||
),
|
||||
existing: util.Pointer(models.CopyReceiverWith(baseReceiver, rm.WithIntegrations(
|
||||
models.CopyIntegrationWith(slackIntegration,
|
||||
im.AddSetting("token", "unencryptedValue"), // This will get encrypted.
|
||||
),
|
||||
))),
|
||||
expectedUpdate: models.CopyReceiverWith(baseReceiver, rm.WithIntegrations(
|
||||
models.CopyIntegrationWith(slackIntegration,
|
||||
im.AddSecureSetting("token", "dW5lbmNyeXB0ZWRWYWx1ZQ==")),
|
||||
), rm.Encrypted(models.Base64Enrypt)),
|
||||
expectedProvenances: map[string]models.Provenance{slackIntegration.UID: models.ProvenanceNone},
|
||||
},
|
||||
{
|
||||
// This test is important for covering the rare case when an existing field is marked as secure.
|
||||
// The UI will receive the field as secure and, if unchanged, will pass it back on update as a secureField instead of a Setting.
|
||||
name: "encrypts previously unencrypted secure fields when passed in as secureFields",
|
||||
user: writer,
|
||||
receiver: models.CopyReceiverWith(baseReceiver, rm.WithIntegrations(
|
||||
models.CopyIntegrationWith(slackIntegration, im.AddSetting("newField", "newValue"))),
|
||||
),
|
||||
secureFields: map[string][]string{slackIntegration.UID: {"token"}},
|
||||
existing: util.Pointer(models.CopyReceiverWith(baseReceiver, rm.WithIntegrations(
|
||||
models.CopyIntegrationWith(slackIntegration,
|
||||
im.AddSetting("token", "unencryptedValue"), // This will get encrypted.
|
||||
),
|
||||
))),
|
||||
expectedUpdate: models.CopyReceiverWith(baseReceiver, rm.WithIntegrations(
|
||||
models.CopyIntegrationWith(slackIntegration,
|
||||
im.AddSetting("newField", "newValue"),
|
||||
im.AddSecureSetting("token", "dW5lbmNyeXB0ZWRWYWx1ZQ==")),
|
||||
), rm.Encrypted(models.Base64Enrypt)),
|
||||
expectedProvenances: map[string]models.Provenance{slackIntegration.UID: models.ProvenanceNone},
|
||||
},
|
||||
{
|
||||
name: "doesn't copy existing unsecure fields",
|
||||
user: writer,
|
||||
@@ -684,8 +722,22 @@ func TestReceiverService_Update(t *testing.T) {
|
||||
sut := createReceiverServiceSut(t, &secretsService)
|
||||
|
||||
if tc.existing != nil {
|
||||
created, err := sut.CreateReceiver(context.Background(), tc.existing, tc.user.GetOrgID(), tc.user)
|
||||
// Create route after receivers as they will be referenced.
|
||||
revision, err := sut.cfgStore.Get(context.Background(), tc.user.GetOrgID())
|
||||
require.NoError(t, err)
|
||||
result, err := revision.CreateReceiver(tc.existing)
|
||||
require.NoError(t, err)
|
||||
|
||||
created, err := PostableApiReceiverToReceiver(result, tc.existing.Provenance)
|
||||
require.NoError(t, err)
|
||||
err = sut.cfgStore.Save(context.Background(), revision, tc.user.GetOrgID())
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, integration := range created.Integrations {
|
||||
target := definitions.EmbeddedContactPoint{UID: integration.UID}
|
||||
err = sut.provisioningStore.SetProvenance(context.Background(), &target, tc.user.GetOrgID(), created.Provenance)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
if tc.version == "" {
|
||||
tc.version = created.Version
|
||||
|
||||
Reference in New Issue
Block a user