fix(alerting): Ensure that alerting.incident-io.url has the correct prefix (#1034)

* fix(alerting): Ensure that alerting.incident-io.url has the correct prefix

* Fix test
This commit is contained in:
TwiN 2025-03-17 19:41:50 -04:00 committed by GitHub
parent 43b0772e7d
commit 46499e13a0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 40 additions and 27 deletions

View File

@ -942,7 +942,7 @@ endpoints:
``` ```
In order to get the required alert source config id and authentication token, you must configure an HTTP alert source. In order to get the required alert source config id and authentication token, you must configure an HTTP alert source.
> **_NOTE:_** the source config id is of the form `api.incident.io/v2/alert_events/http/$ID` and the token is expected to be passed as a bearer token like so: `Authorization: Bearer $TOKEN` > **_NOTE:_** the source config id is of the form `https://api.incident.io/v2/alert_events/http/$ID` and the token is expected to be passed as a bearer token like so: `Authorization: Bearer $TOKEN`
#### Configuring JetBrains Space alerts #### Configuring JetBrains Space alerts

View File

@ -23,6 +23,7 @@ const (
var ( var (
ErrURLNotSet = errors.New("url not set") ErrURLNotSet = errors.New("url not set")
ErrURLNotPrefixedWithRestAPIURL = fmt.Errorf("url must be prefixed with %s", restAPIUrl)
ErrDuplicateGroupOverride = errors.New("duplicate group override") ErrDuplicateGroupOverride = errors.New("duplicate group override")
ErrAuthTokenNotSet = errors.New("auth-token not set") ErrAuthTokenNotSet = errors.New("auth-token not set")
) )
@ -38,6 +39,9 @@ func (cfg *Config) Validate() error {
if len(cfg.URL) == 0 { if len(cfg.URL) == 0 {
return ErrURLNotSet return ErrURLNotSet
} }
if !strings.HasPrefix(cfg.URL, restAPIUrl) {
return ErrURLNotPrefixedWithRestAPIURL
}
if len(cfg.AuthToken) == 0 { if len(cfg.AuthToken) == 0 {
return ErrAuthTokenNotSet return ErrAuthTokenNotSet
} }
@ -113,7 +117,7 @@ func (provider *AlertProvider) Send(ep *endpoint.Endpoint, alert *alert.Alert, r
err = json.NewDecoder(response.Body).Decode(&incidentioResponse) err = json.NewDecoder(response.Body).Decode(&incidentioResponse)
if err != nil { if err != nil {
// Silently fail. We don't want to create tons of alerts just because we failed to parse the body. // Silently fail. We don't want to create tons of alerts just because we failed to parse the body.
logr.Errorf("[incident-io.Send] Ran into error decoding pagerduty response: %s", err.Error()) logr.Errorf("[incidentio.Send] Ran into error decoding pagerduty response: %s", err.Error())
} }
alert.ResolveKey = incidentioResponse.DeduplicationKey alert.ResolveKey = incidentioResponse.DeduplicationKey
return err return err
@ -155,10 +159,9 @@ func (provider *AlertProvider) buildRequestBody(cfg *Config, ep *endpoint.Endpoi
if len(alert.GetDescription()) > 0 { if len(alert.GetDescription()) > 0 {
message += " with the following description: " + alert.GetDescription() message += " with the following description: " + alert.GetDescription()
} }
message += fmt.Sprintf(" and the following conditions: %s ", formattedConditionResults) message += fmt.Sprintf(" and the following conditions: %s ", formattedConditionResults)
var body []byte var body []byte
alertSourceID := strings.Split(cfg.URL, restAPIUrl)[1] alertSourceID := strings.TrimPrefix(cfg.URL, restAPIUrl)
body, _ = json.Marshal(Body{ body, _ = json.Marshal(Body{
AlertSourceConfigID: alertSourceID, AlertSourceConfigID: alertSourceID,
Title: "Gatus: " + ep.DisplayName(), Title: "Gatus: " + ep.DisplayName(),

View File

@ -23,12 +23,22 @@ func TestAlertProvider_Validate(t *testing.T) {
name: "valid", name: "valid",
provider: AlertProvider{ provider: AlertProvider{
DefaultConfig: Config{ DefaultConfig: Config{
URL: "some-id", URL: "https://api.incident.io/v2/alert_events/http/some-id",
AuthToken: "some-token", AuthToken: "some-token",
}, },
}, },
expected: true, expected: true,
}, },
{
name: "invalid-url",
provider: AlertProvider{
DefaultConfig: Config{
URL: "id-without-rest-api-url-as-prefix",
AuthToken: "some-token",
},
},
expected: false,
},
{ {
name: "invalid-missing-auth-token", name: "invalid-missing-auth-token",
provider: AlertProvider{ provider: AlertProvider{
@ -52,9 +62,9 @@ func TestAlertProvider_Validate(t *testing.T) {
provider: AlertProvider{ provider: AlertProvider{
DefaultConfig: Config{ DefaultConfig: Config{
AuthToken: "some-token", AuthToken: "some-token",
URL: "some-id", URL: "https://api.incident.io/v2/alert_events/http/some-id",
}, },
Overrides: []Override{{Group: "core", Config: Config{URL: "another-id"}}}, Overrides: []Override{{Group: "core", Config: Config{URL: "https://api.incident.io/v2/alert_events/http/another-id"}}},
}, },
expected: true, expected: true,
}, },
@ -258,67 +268,67 @@ func TestAlertProvider_GetConfig(t *testing.T) {
{ {
Name: "provider-no-override-specify-no-group-should-default", Name: "provider-no-override-specify-no-group-should-default",
Provider: AlertProvider{ Provider: AlertProvider{
DefaultConfig: Config{URL: "some-id", AuthToken: "some-token"}, DefaultConfig: Config{URL: "https://api.incident.io/v2/alert_events/http/some-id", AuthToken: "some-token"},
Overrides: nil, Overrides: nil,
}, },
InputGroup: "", InputGroup: "",
InputAlert: alert.Alert{}, InputAlert: alert.Alert{},
ExpectedOutput: Config{URL: "some-id", AuthToken: "some-token"}, ExpectedOutput: Config{URL: "https://api.incident.io/v2/alert_events/http/some-id", AuthToken: "some-token"},
}, },
{ {
Name: "provider-no-override-specify-group-should-default", Name: "provider-no-override-specify-group-should-default",
Provider: AlertProvider{ Provider: AlertProvider{
DefaultConfig: Config{URL: "some-id", AuthToken: "some-token"}, DefaultConfig: Config{URL: "https://api.incident.io/v2/alert_events/http/some-id", AuthToken: "some-token"},
Overrides: nil, Overrides: nil,
}, },
InputGroup: "group", InputGroup: "group",
InputAlert: alert.Alert{}, InputAlert: alert.Alert{},
ExpectedOutput: Config{URL: "some-id", AuthToken: "some-token"}, ExpectedOutput: Config{URL: "https://api.incident.io/v2/alert_events/http/some-id", AuthToken: "some-token"},
}, },
{ {
Name: "provider-with-override-specify-no-group-should-default", Name: "provider-with-override-specify-no-group-should-default",
Provider: AlertProvider{ Provider: AlertProvider{
DefaultConfig: Config{URL: "some-id", AuthToken: "some-token"}, DefaultConfig: Config{URL: "https://api.incident.io/v2/alert_events/http/some-id", AuthToken: "some-token"},
Overrides: []Override{ Overrides: []Override{
{ {
Group: "group", Group: "group",
Config: Config{URL: "diff-id"}, Config: Config{URL: "https://api.incident.io/v2/alert_events/http/diff-id"},
}, },
}, },
}, },
InputGroup: "", InputGroup: "",
InputAlert: alert.Alert{}, InputAlert: alert.Alert{},
ExpectedOutput: Config{URL: "some-id", AuthToken: "some-token"}, ExpectedOutput: Config{URL: "https://api.incident.io/v2/alert_events/http/some-id", AuthToken: "some-token"},
}, },
{ {
Name: "provider-with-override-specify-group-should-override", Name: "provider-with-override-specify-group-should-override",
Provider: AlertProvider{ Provider: AlertProvider{
DefaultConfig: Config{URL: "some-id", AuthToken: "some-token"}, DefaultConfig: Config{URL: "https://api.incident.io/v2/alert_events/http/some-id", AuthToken: "some-token"},
Overrides: []Override{ Overrides: []Override{
{ {
Group: "group", Group: "group",
Config: Config{URL: "diff-id", AuthToken: "some-token"}, Config: Config{URL: "https://api.incident.io/v2/alert_events/http/diff-id", AuthToken: "some-token"},
}, },
}, },
}, },
InputGroup: "group", InputGroup: "group",
InputAlert: alert.Alert{}, InputAlert: alert.Alert{},
ExpectedOutput: Config{URL: "diff-id", AuthToken: "some-token"}, ExpectedOutput: Config{URL: "https://api.incident.io/v2/alert_events/http/diff-id", AuthToken: "some-token"},
}, },
{ {
Name: "provider-with-group-override-and-alert-override--alert-override-should-take-precedence", Name: "provider-with-group-override-and-alert-override--alert-override-should-take-precedence",
Provider: AlertProvider{ Provider: AlertProvider{
DefaultConfig: Config{URL: "some-id", AuthToken: "some-token"}, DefaultConfig: Config{URL: "https://api.incident.io/v2/alert_events/http/some-id", AuthToken: "some-token"},
Overrides: []Override{ Overrides: []Override{
{ {
Group: "group", Group: "group",
Config: Config{URL: "diff-id", AuthToken: "some-token"}, Config: Config{URL: "https://api.incident.io/v2/alert_events/http/diff-id", AuthToken: "some-token"},
}, },
}, },
}, },
InputGroup: "group", InputGroup: "group",
InputAlert: alert.Alert{ProviderOverride: map[string]any{"url": "another-id"}}, InputAlert: alert.Alert{ProviderOverride: map[string]any{"url": "https://api.incident.io/v2/alert_events/http/another-id"}},
ExpectedOutput: Config{URL: "another-id", AuthToken: "some-token"}, ExpectedOutput: Config{URL: "https://api.incident.io/v2/alert_events/http/another-id", AuthToken: "some-token"},
}, },
} }
for _, scenario := range scenarios { for _, scenario := range scenarios {
@ -346,7 +356,7 @@ func TestAlertProvider_ValidateWithOverride(t *testing.T) {
providerWithInvalidOverrideGroup := AlertProvider{ providerWithInvalidOverrideGroup := AlertProvider{
Overrides: []Override{ Overrides: []Override{
{ {
Config: Config{URL: "some-id", AuthToken: "some-token"}, Config: Config{URL: "https://api.incident.io/v2/alert_events/http/some-id", AuthToken: "some-token"},
Group: "", Group: "",
}, },
}, },
@ -366,10 +376,10 @@ func TestAlertProvider_ValidateWithOverride(t *testing.T) {
t.Error("provider integration key shouldn't have been valid") t.Error("provider integration key shouldn't have been valid")
} }
providerWithValidOverride := AlertProvider{ providerWithValidOverride := AlertProvider{
DefaultConfig: Config{URL: "nice-id", AuthToken: "some-token"}, DefaultConfig: Config{URL: "https://api.incident.io/v2/alert_events/http/nice-id", AuthToken: "some-token"},
Overrides: []Override{ Overrides: []Override{
{ {
Config: Config{URL: "very-good-id", AuthToken: "some-token"}, Config: Config{URL: "https://api.incident.io/v2/alert_events/http/very-good-id", AuthToken: "some-token"},
Group: "group", Group: "group",
}, },
}, },