Alerting: Add OAuth2 Support for Webhook Receiver (#106302)

* Add to available channels

* Export

* Fix bug in deeply nested secrets

BE: Slice re-use bug when traversing deeply.

FE: Only at most one level of nesting was being taken into account
when determining secureFields keys. This change adds a new field on
NotificationChannelOption: secureFieldKey. This is populated on API GET via
transform. This change gives us the option to hardcode secureFieldKey in the
backend and no longer calculate the key via settings topology.

* Update grafana/alerting to 3e20fda3b872

* Prettier

* Linting

* Fix IntegrationConfig test to catch secure field mismatch
This commit is contained in:
Matthew Jacobson
2025-06-12 23:00:09 +02:00
committed by GitHub
parent 5135d5c87d
commit 0016b57486
16 changed files with 697 additions and 82 deletions
+9 -4
View File
@@ -191,8 +191,12 @@ func (f IntegrationFieldPath) String() string {
return strings.Join(f, ".")
}
func (f IntegrationFieldPath) Append(segment string) IntegrationFieldPath {
return append(f, segment)
func (f IntegrationFieldPath) With(segment string) IntegrationFieldPath {
// Copy the existing path to avoid modifying the original slice.
newPath := make(IntegrationFieldPath, len(f)+1)
copy(newPath, f)
newPath[len(newPath)-1] = segment
return newPath
}
// IntegrationConfigFromType returns an integration configuration for a given integration type. If the integration type is
@@ -250,11 +254,12 @@ func (config *IntegrationConfig) GetSecretFields() []IntegrationFieldPath {
func traverseFields(flds map[string]IntegrationField, parentPath IntegrationFieldPath, predicate func(i IntegrationField) bool) []IntegrationFieldPath {
var result []IntegrationFieldPath
for key, field := range flds {
path := parentPath.With(key)
if predicate(field) {
result = append(result, parentPath.Append(key))
result = append(result, path)
}
if len(field.Fields) > 0 {
result = append(result, traverseFields(field.Fields, parentPath.Append(key), predicate)...)
result = append(result, traverseFields(field.Fields, path, predicate)...)
}
}
return result
@@ -244,11 +244,14 @@ func TestIntegrationConfig(t *testing.T) {
allSecrets[key] = struct{}{}
}
for field := range config.Fields {
_, isSecret := allSecrets[field]
assert.Equalf(t, isSecret, config.IsSecureField(NewIntegrationFieldPath(field)), "field '%s' is expected to be secret", field)
secretFields := config.GetSecretFields()
for _, path := range secretFields {
_, isSecret := allSecrets[path.String()]
assert.Equalf(t, isSecret, config.IsSecureField(path), "field '%s' is expected to be secret", path)
delete(allSecrets, path.String())
}
assert.False(t, config.IsSecureField(IntegrationFieldPath{"__--**unknown_field**--__"}))
assert.Empty(t, allSecrets, "mismatched secret fields for integration type %s: %v", integrationType, allSecrets)
})
}