Skip to content

Commit

Permalink
support loading webhook URL from a file (#3223)
Browse files Browse the repository at this point in the history
* support loading webhook URL from a file

/cc #2498

Signed-off-by: Simon Rozet <me@simonrozet.com>

* notify/webhook: add test for reading url from file

Signed-off-by: Simon Rozet <me@simonrozet.com>

* notify/pushover: add tests for reading secrets from files

Signed-off-by: Simon Rozet <me@simonrozet.com>

---------

Signed-off-by: Simon Rozet <me@simonrozet.com>
  • Loading branch information
sr committed Mar 3, 2023
1 parent 44bb5c9 commit 41eb121
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 8 deletions.
16 changes: 11 additions & 5 deletions config/notifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,8 @@ type WebhookConfig struct {
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`

// URL to send POST request to.
URL *SecretURL `yaml:"url" json:"url"`
URL *SecretURL `yaml:"url" json:"url"`
URLFile string `yaml:"url_file" json:"url_file"`

// MaxAlerts is the maximum number of alerts to be sent per webhook message.
// Alerts exceeding this threshold will be truncated. Setting this to 0
Expand All @@ -488,11 +489,16 @@ func (c *WebhookConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
if err := unmarshal((*plain)(c)); err != nil {
return err
}
if c.URL == nil {
return fmt.Errorf("missing URL in webhook config")
if c.URL == nil && c.URLFile == "" {
return fmt.Errorf("one of url or url_file must be configured")
}
if c.URL.Scheme != "https" && c.URL.Scheme != "http" {
return fmt.Errorf("scheme required for webhook url")
if c.URL != nil && c.URLFile != "" {
return fmt.Errorf("at most one of url & url_file must be configured")
}
if c.URL != nil {
if c.URL.Scheme != "https" && c.URL.Scheme != "http" {
return fmt.Errorf("scheme required for webhook url")
}
}
return nil
}
Expand Down
20 changes: 19 additions & 1 deletion config/notifiers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,25 @@ func TestWebhookURLIsPresent(t *testing.T) {
var cfg WebhookConfig
err := yaml.UnmarshalStrict([]byte(in), &cfg)

expected := "missing URL in webhook config"
expected := "one of url or url_file must be configured"

if err == nil {
t.Fatalf("no error returned, expected:\n%v", expected)
}
if err.Error() != expected {
t.Errorf("\nexpected:\n%v\ngot:\n%v", expected, err.Error())
}
}

func TestWebhookURLOrURLFile(t *testing.T) {
in := `
url: 'http://example.com'
url_file: 'http://example.com'
`
var cfg WebhookConfig
err := yaml.UnmarshalStrict([]byte(in), &cfg)

expected := "at most one of url & url_file must be configured"

if err == nil {
t.Fatalf("no error returned, expected:\n%v", expected)
Expand Down
4 changes: 3 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,7 @@ Pushover notifications are sent via the [Pushover API](https://pushover.net/api)
# Whether to notify about resolved alerts.
[ send_resolved: <boolean> | default = true ]

# The recipient user's key.
# The recipient user's key.
# user_key and user_key_file are mutually exclusive.
user_key: <secret>
user_key_file: <filepath>
Expand Down Expand Up @@ -1116,7 +1116,9 @@ The webhook receiver allows configuring a generic receiver.
[ send_resolved: <boolean> | default = true ]

# The endpoint to send HTTP POST requests to.
# url and url_file are mutually exclusive.
url: <secret>
url_file: <filepath>

# The HTTP client's configuration.
[ http_config: <http_config> | default = global.http_config ]
Expand Down
51 changes: 51 additions & 0 deletions notify/pushover/pushover_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package pushover

import (
"fmt"
"os"
"testing"

"github.com/go-kit/log"
Expand Down Expand Up @@ -59,3 +60,53 @@ func TestPushoverRedactedURL(t *testing.T) {

test.AssertNotifyLeaksNoSecret(ctx, t, notifier, key, token)
}

func TestPushoverReadingUserKeyFromFile(t *testing.T) {
ctx, apiURL, fn := test.GetContextWithCancelingURL()
defer fn()

const userKey = "user key"
f, err := os.CreateTemp("", "pushover_user_key")
require.NoError(t, err, "creating temp file failed")
_, err = f.WriteString(userKey)
require.NoError(t, err, "writing to temp file failed")

notifier, err := New(
&config.PushoverConfig{
UserKeyFile: f.Name(),
Token: config.Secret("token"),
HTTPConfig: &commoncfg.HTTPClientConfig{},
},
test.CreateTmpl(t),
log.NewNopLogger(),
)
notifier.apiURL = apiURL.String()
require.NoError(t, err)

test.AssertNotifyLeaksNoSecret(ctx, t, notifier, userKey)
}

func TestPushoverReadingTokenFromFile(t *testing.T) {
ctx, apiURL, fn := test.GetContextWithCancelingURL()
defer fn()

const token = "token"
f, err := os.CreateTemp("", "pushover_token")
require.NoError(t, err, "creating temp file failed")
_, err = f.WriteString(token)
require.NoError(t, err, "writing to temp file failed")

notifier, err := New(
&config.PushoverConfig{
UserKey: config.Secret("user key"),
TokenFile: f.Name(),
HTTPConfig: &commoncfg.HTTPClientConfig{},
},
test.CreateTmpl(t),
log.NewNopLogger(),
)
notifier.apiURL = apiURL.String()
require.NoError(t, err)

test.AssertNotifyLeaksNoSecret(ctx, t, notifier, token)
}
14 changes: 13 additions & 1 deletion notify/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"fmt"
"io"
"net/http"
"os"

"github.com/go-kit/log"
"github.com/go-kit/log/level"
Expand Down Expand Up @@ -101,7 +102,18 @@ func (n *Notifier) Notify(ctx context.Context, alerts ...*types.Alert) (bool, er
return false, err
}

resp, err := notify.PostJSON(ctx, n.client, n.conf.URL.String(), &buf)
var url string
if n.conf.URL != nil {
url = n.conf.URL.String()
} else {
content, err := os.ReadFile(n.conf.URLFile)
if err != nil {
return false, fmt.Errorf("read url_file: %w", err)
}
url = string(content)
}

resp, err := notify.PostJSON(ctx, n.client, url, &buf)
if err != nil {
return true, notify.RedactURL(err)
}
Expand Down
23 changes: 23 additions & 0 deletions notify/webhook/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"io"
"net/http"
"net/url"
"os"
"testing"

"github.com/go-kit/log"
Expand Down Expand Up @@ -116,3 +117,25 @@ func TestWebhookRedactedURL(t *testing.T) {

test.AssertNotifyLeaksNoSecret(ctx, t, notifier, secret)
}

func TestWebhookReadingURLFromFile(t *testing.T) {
ctx, u, fn := test.GetContextWithCancelingURL()
defer fn()

f, err := os.CreateTemp("", "webhook_url")
require.NoError(t, err, "creating temp file failed")
_, err = f.WriteString(u.String())
require.NoError(t, err, "writing to temp file failed")

notifier, err := New(
&config.WebhookConfig{
URLFile: f.Name(),
HTTPConfig: &commoncfg.HTTPClientConfig{},
},
test.CreateTmpl(t),
log.NewNopLogger(),
)
require.NoError(t, err)

test.AssertNotifyLeaksNoSecret(ctx, t, notifier, u.String())
}

0 comments on commit 41eb121

Please sign in to comment.