Hello community,
here is the log from the commit of package golang-github-prometheus-alertmanager for openSUSE:Factory checked in at 2019-04-17 10:09:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/golang-github-prometheus-alertmanager (Old)
and /work/SRC/openSUSE:Factory/.golang-github-prometheus-alertmanager.new.17052 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "golang-github-prometheus-alertmanager"
Wed Apr 17 10:09:50 2019 rev:3 rq:694777 version:0.16.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/golang-github-prometheus-alertmanager/golang-github-prometheus-alertmanager.changes 2019-02-24 17:13:58.736465744 +0100
+++ /work/SRC/openSUSE:Factory/.golang-github-prometheus-alertmanager.new.17052/golang-github-prometheus-alertmanager.changes 2019-04-17 10:10:03.734894524 +0200
@@ -1,0 +2,8 @@
+Tue Apr 16 08:15:25 UTC 2019 - Jan Fajerski
+
+- Update to 0.16.2
+ + Bug Fixes:
+ * Redact notifier URL from logs to not leak secrets embedded in the URL
+ * Allow sending of unauthenticated SMTP requests when smtp_auth_username is not supplied
+
+-------------------------------------------------------------------
Old:
----
alertmanager-0.16.1.tar.xz
New:
----
alertmanager-0.16.2.tar.xz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ golang-github-prometheus-alertmanager.spec ++++++
--- /var/tmp/diff_new_pack.t2b0tj/_old 2019-04-17 10:10:11.078902348 +0200
+++ /var/tmp/diff_new_pack.t2b0tj/_new 2019-04-17 10:10:11.082902353 +0200
@@ -19,7 +19,7 @@
%{go_nostrip}
Name: golang-github-prometheus-alertmanager
-Version: 0.16.1
+Version: 0.16.2
Release: 0
Summary: Prometheus Alertmanager
License: Apache-2.0
++++++ _service ++++++
--- /var/tmp/diff_new_pack.t2b0tj/_old 2019-04-17 10:10:11.118902391 +0200
+++ /var/tmp/diff_new_pack.t2b0tj/_new 2019-04-17 10:10:11.118902391 +0200
@@ -3,8 +3,9 @@
<param name="url">https://github.com/prometheus/alertmanager.git</param>
<param name="scm">git</param>
<param name="exclude">.git</param>
- <param name="versionformat">0.16.1</param>
- <param name="revision">v0.16.1</param>
+ <param name="exclude">.github</param>
+ <param name="versionformat">0.16.2</param>
+ <param name="revision">v0.16.2</param>
</service>
<service name="recompress" mode="disabled">
<param name="file">alertmanager-*.tar</param>
++++++ alertmanager-0.16.1.tar.xz -> alertmanager-0.16.2.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/alertmanager-0.16.1/CHANGELOG.md new/alertmanager-0.16.2/CHANGELOG.md
--- old/alertmanager-0.16.1/CHANGELOG.md 2019-02-08 11:39:46.000000000 +0100
+++ new/alertmanager-0.16.2/CHANGELOG.md 2019-04-05 14:25:19.000000000 +0200
@@ -1,3 +1,12 @@
+## 0.16.2 / 2019-04-03
+
+Updating to v0.16.2 is recommended for all users using the Slack, Pagerduty,
+Hipchat, Wechat, VictorOps and Pushover notifier, as connection errors could
+leak secrets embedded in the notifier's URL to stdout.
+
+* [BUGFIX] Redact notifier URL from logs to not leak secrets embedded in the URL (#1822, #1825)
+* [BUGFIX] Allow sending of unauthenticated SMTP requests when `smtp_auth_username` is not supplied (#1739)
+
## 0.16.1 / 2019-01-31
* [BUGFIX] Do not populate cluster info if clustering is disabled in API v2 (#1726)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/alertmanager-0.16.1/Makefile new/alertmanager-0.16.2/Makefile
--- old/alertmanager-0.16.1/Makefile 2019-02-08 11:39:46.000000000 +0100
+++ new/alertmanager-0.16.2/Makefile 2019-04-05 14:25:19.000000000 +0200
@@ -28,7 +28,7 @@
build-all: assets apiv2 build
assets: ui/app/script.js ui/app/index.html ui/app/lib template/default.tmpl
- cd $(PREFIX)/asset && $(GO) generate
+ GO111MODULE=$(GO111MODULE) $(GO) generate ./asset
@$(GOFMT) -w ./asset
ui/app/script.js: $(shell find ui/app/src -iname *.elm) api/v2/openapi.yaml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/alertmanager-0.16.1/VERSION new/alertmanager-0.16.2/VERSION
--- old/alertmanager-0.16.1/VERSION 2019-02-08 11:39:45.000000000 +0100
+++ new/alertmanager-0.16.2/VERSION 2019-04-05 14:25:19.000000000 +0200
@@ -1 +1 @@
-0.16.1
+0.16.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/alertmanager-0.16.1/notify/impl.go new/alertmanager-0.16.2/notify/impl.go
--- old/alertmanager-0.16.1/notify/impl.go 2019-02-08 11:39:46.000000000 +0100
+++ new/alertmanager-0.16.2/notify/impl.go 2019-04-05 14:25:19.000000000 +0200
@@ -221,6 +221,13 @@
// auth resolves a string of authentication mechanisms.
func (n *Email) auth(mechs string) (smtp.Auth, error) {
username := n.conf.AuthUsername
+
+ // If no username is set, keep going without authentication.
+ if n.conf.AuthUsername == "" {
+ level.Debug(n.logger).Log("msg", "smtp_auth_username is not configured. Attempting to send email without authenticating")
+ return nil, nil
+ }
+
err := &types.MultiError{}
for _, mech := range strings.Split(mechs, " ") {
switch mech {
@@ -464,11 +471,16 @@
conf *config.PagerdutyConfig
tmpl *template.Template
logger log.Logger
+ apiV1 string // for tests.
}
// NewPagerDuty returns a new PagerDuty notifier.
func NewPagerDuty(c *config.PagerdutyConfig, t *template.Template, l log.Logger) *PagerDuty {
- return &PagerDuty{conf: c, tmpl: t, logger: l}
+ n := &PagerDuty{conf: c, tmpl: t, logger: l}
+ if c.ServiceKey != "" {
+ n.apiV1 = "https://events.pagerduty.com/generic/2010-04-15/create_event.json"
+ }
+ return n
}
const (
@@ -533,12 +545,6 @@
Details: details,
}
- apiURL, err := url.Parse("https://events.pagerduty.com/generic/2010-04-15/create_event.json")
- if err != nil {
- return false, err
- }
- n.conf.URL = &config.URL{apiURL}
-
if eventType == pagerDutyEventTrigger {
msg.Client = tmpl(n.conf.Client)
msg.ClientURL = tmpl(n.conf.ClientURL)
@@ -553,7 +559,7 @@
return false, err
}
- resp, err := post(ctx, c, n.conf.URL.String(), contentTypeJSON, &buf)
+ resp, err := post(ctx, c, n.apiV1, contentTypeJSON, &buf)
if err != nil {
return true, err
}
@@ -664,7 +670,7 @@
return false, err
}
- if n.conf.ServiceKey != "" {
+ if n.apiV1 != "" {
return n.notifyV1(ctx, c, eventType, key, data, details, as...)
}
return n.notifyV2(ctx, c, eventType, key, data, details, as...)
@@ -838,9 +844,10 @@
return false, err
}
- resp, err := post(ctx, c, n.conf.APIURL.String(), contentTypeJSON, &buf)
+ u := n.conf.APIURL.String()
+ resp, err := post(ctx, c, u, contentTypeJSON, &buf)
if err != nil {
- return true, err
+ return true, redactURL(err)
}
resp.Body.Close()
@@ -927,7 +934,7 @@
resp, err := post(ctx, c, apiURL.String(), contentTypeJSON, &buf)
if err != nil {
- return true, err
+ return true, redactURL(err)
}
defer resp.Body.Close()
@@ -1028,7 +1035,7 @@
resp, err := c.Do(req.WithContext(ctx))
if err != nil {
- return true, err
+ return true, redactURL(err)
}
defer resp.Body.Close()
@@ -1079,7 +1086,7 @@
resp, err := c.Do(req.WithContext(ctx))
if err != nil {
- return true, err
+ return true, redactURL(err)
}
defer resp.Body.Close()
@@ -1308,7 +1315,7 @@
resp, err := post(ctx, c, apiURL.String(), contentTypeJSON, buf)
if err != nil {
- return true, err
+ return true, redactURL(err)
}
defer resp.Body.Close()
@@ -1396,11 +1403,12 @@
conf *config.PushoverConfig
tmpl *template.Template
logger log.Logger
+ apiURL string // for tests.
}
// NewPushover returns a new Pushover notifier.
func NewPushover(c *config.PushoverConfig, t *template.Template, l log.Logger) *Pushover {
- return &Pushover{conf: c, tmpl: t, logger: l}
+ return &Pushover{conf: c, tmpl: t, logger: l, apiURL: "https://api.pushover.net/1/messages.json"}
}
// Notify implements the Notifier interface.
@@ -1465,13 +1473,13 @@
return false, err
}
- apiURL := "https://api.pushover.net/1/messages.json"
- u, err := url.Parse(apiURL)
+ u, err := url.Parse(n.apiURL)
if err != nil {
return false, err
}
u.RawQuery = parameters.Encode()
- level.Debug(n.logger).Log("msg", "Sending Pushover message", "incident", key, "url", u.String())
+ // Don't log the URL as it contains secret data (see #1825).
+ level.Debug(n.logger).Log("msg", "Sending Pushover message", "incident", key)
c, err := commoncfg.NewClientFromConfig(*n.conf.HTTPConfig, "pushover")
if err != nil {
@@ -1480,7 +1488,7 @@
resp, err := post(ctx, c, u.String(), "text/plain", nil)
if err != nil {
- return true, err
+ return true, redactURL(err)
}
defer resp.Body.Close()
@@ -1559,6 +1567,16 @@
return fmt.Sprintf("%x", h.Sum(nil))
}
+// redactURL removes the URL part from an error of *url.Error type.
+func redactURL(err error) error {
+ e, ok := err.(*url.Error)
+ if !ok {
+ return err
+ }
+ e.URL = "<redacted>"
+ return e
+}
+
func post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest("POST", url, body)
if err != nil {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/alertmanager-0.16.1/notify/impl_test.go new/alertmanager-0.16.2/notify/impl_test.go
--- old/alertmanager-0.16.1/notify/impl_test.go 2019-02-08 11:39:45.000000000 +0100
+++ new/alertmanager-0.16.2/notify/impl_test.go 2019-04-05 14:25:19.000000000 +0200
@@ -19,19 +19,76 @@
"fmt"
"io/ioutil"
"net/http"
+ "net/http/httptest"
"net/url"
"testing"
"time"
"github.com/go-kit/kit/log"
+ commoncfg "github.com/prometheus/common/config"
+ "github.com/prometheus/common/model"
"github.com/stretchr/testify/require"
"github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/template"
"github.com/prometheus/alertmanager/types"
- "github.com/prometheus/common/model"
)
+// getContextWithCancelingURL returns a context that gets canceled when a
+// client does a GET request to the returned URL.
+// Handlers passed to the function will be invoked in order before the context gets canceled.
+func getContextWithCancelingURL(h ...func(w http.ResponseWriter, r *http.Request)) (context.Context, *url.URL, func()) {
+ done := make(chan struct{})
+ ctx, cancel := context.WithCancel(context.Background())
+ i := 0
+
+ srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if i < len(h) {
+ h[i](w, r)
+ } else {
+ cancel()
+ <-done
+ }
+ i++
+ }))
+
+ // No need to check the error since httptest.NewServer always return a valid URL.
+ u, _ := url.Parse(srv.URL)
+
+ return ctx, u, func() {
+ close(done)
+ srv.Close()
+ }
+}
+
+// assertNotifyLeaksNoSecret calls the Notify() method of the notifier, expects
+// it to fail because the context is canceled by the server and checks that no
+// secret data is leaked in the error message returned by Notify().
+func assertNotifyLeaksNoSecret(t *testing.T, ctx context.Context, n Notifier, secret ...string) {
+ t.Helper()
+ require.NotEmpty(t, secret)
+
+ ctx = WithGroupKey(ctx, "1")
+ ok, err := n.Notify(ctx, []*types.Alert{
+ &types.Alert{
+ Alert: model.Alert{
+ Labels: model.LabelSet{
+ "lbl1": "val1",
+ },
+ StartsAt: time.Now(),
+ EndsAt: time.Now().Add(time.Hour),
+ },
+ },
+ }...)
+
+ require.Error(t, err)
+ require.Contains(t, err.Error(), context.Canceled.Error())
+ for _, s := range secret {
+ require.NotContains(t, err.Error(), s)
+ }
+ require.True(t, ok)
+}
+
func TestWebhookRetry(t *testing.T) {
u, err := url.Parse("http://example.com")
if err != nil {
@@ -67,6 +124,42 @@
}
}
+func TestPagerDutyRedactedURLV1(t *testing.T) {
+ ctx, u, fn := getContextWithCancelingURL()
+ defer fn()
+
+ key := "01234567890123456789012345678901"
+ notifier := NewPagerDuty(
+ &config.PagerdutyConfig{
+ ServiceKey: config.Secret(key),
+ HTTPConfig: &commoncfg.HTTPClientConfig{},
+ },
+ createTmpl(t),
+ log.NewNopLogger(),
+ )
+ notifier.apiV1 = u.String()
+
+ assertNotifyLeaksNoSecret(t, ctx, notifier, key)
+}
+
+func TestPagerDutyRedactedURLV2(t *testing.T) {
+ ctx, u, fn := getContextWithCancelingURL()
+ defer fn()
+
+ key := "01234567890123456789012345678901"
+ notifier := NewPagerDuty(
+ &config.PagerdutyConfig{
+ URL: &config.URL{u},
+ RoutingKey: config.Secret(key),
+ HTTPConfig: &commoncfg.HTTPClientConfig{},
+ },
+ createTmpl(t),
+ log.NewNopLogger(),
+ )
+
+ assertNotifyLeaksNoSecret(t, ctx, notifier, key)
+}
+
func TestSlackRetry(t *testing.T) {
notifier := new(Slack)
for statusCode, expected := range retryTests(defaultRetryCodes()) {
@@ -75,6 +168,22 @@
}
}
+func TestSlackRedactedURL(t *testing.T) {
+ ctx, u, fn := getContextWithCancelingURL()
+ defer fn()
+
+ notifier := NewSlack(
+ &config.SlackConfig{
+ APIURL: &config.SecretURL{URL: u},
+ HTTPConfig: &commoncfg.HTTPClientConfig{},
+ },
+ createTmpl(t),
+ log.NewNopLogger(),
+ )
+
+ assertNotifyLeaksNoSecret(t, ctx, notifier, u.String())
+}
+
func TestHipchatRetry(t *testing.T) {
notifier := new(Hipchat)
retryCodes := append(defaultRetryCodes(), http.StatusTooManyRequests)
@@ -84,6 +193,24 @@
}
}
+func TestHipchatRedactedURL(t *testing.T) {
+ ctx, u, fn := getContextWithCancelingURL()
+ defer fn()
+
+ token := "secret_token"
+ notifier := NewHipchat(
+ &config.HipchatConfig{
+ APIURL: &config.URL{URL: u},
+ AuthToken: config.Secret(token),
+ HTTPConfig: &commoncfg.HTTPClientConfig{},
+ },
+ createTmpl(t),
+ log.NewNopLogger(),
+ )
+
+ assertNotifyLeaksNoSecret(t, ctx, notifier, token)
+}
+
func TestOpsGenieRetry(t *testing.T) {
notifier := new(OpsGenie)
@@ -94,6 +221,24 @@
}
}
+func TestOpsGenieRedactedURL(t *testing.T) {
+ ctx, u, fn := getContextWithCancelingURL()
+ defer fn()
+
+ key := "key"
+ notifier := NewOpsGenie(
+ &config.OpsGenieConfig{
+ APIURL: &config.URL{URL: u},
+ APIKey: config.Secret(key),
+ HTTPConfig: &commoncfg.HTTPClientConfig{},
+ },
+ createTmpl(t),
+ log.NewNopLogger(),
+ )
+
+ assertNotifyLeaksNoSecret(t, ctx, notifier, key)
+}
+
func TestVictorOpsRetry(t *testing.T) {
notifier := new(VictorOps)
for statusCode, expected := range retryTests(defaultRetryCodes()) {
@@ -102,6 +247,24 @@
}
}
+func TestVictorOpsRedactedURL(t *testing.T) {
+ ctx, u, fn := getContextWithCancelingURL()
+ defer fn()
+
+ secret := "secret"
+ notifier := NewVictorOps(
+ &config.VictorOpsConfig{
+ APIURL: &config.URL{URL: u},
+ APIKey: config.Secret(secret),
+ HTTPConfig: &commoncfg.HTTPClientConfig{},
+ },
+ createTmpl(t),
+ log.NewNopLogger(),
+ )
+
+ assertNotifyLeaksNoSecret(t, ctx, notifier, secret)
+}
+
func TestPushoverRetry(t *testing.T) {
notifier := new(Pushover)
for statusCode, expected := range retryTests(defaultRetryCodes()) {
@@ -110,6 +273,25 @@
}
}
+func TestPushoverRedactedURL(t *testing.T) {
+ ctx, u, fn := getContextWithCancelingURL()
+ defer fn()
+
+ key, token := "user_key", "token"
+ notifier := NewPushover(
+ &config.PushoverConfig{
+ UserKey: config.Secret(key),
+ Token: config.Secret(token),
+ HTTPConfig: &commoncfg.HTTPClientConfig{},
+ },
+ createTmpl(t),
+ log.NewNopLogger(),
+ )
+ notifier.apiURL = u.String()
+
+ assertNotifyLeaksNoSecret(t, ctx, notifier, key, token)
+}
+
func retryTests(retryCodes []int) map[int]bool {
tests := map[int]bool{
// 1xx
@@ -295,7 +477,7 @@
func TestEmailConfigNoAuthMechs(t *testing.T) {
email := &Email{
- conf: &config.EmailConfig{}, tmpl: &template.Template{}, logger: log.NewNopLogger(),
+ conf: &config.EmailConfig{AuthUsername: "test"}, tmpl: &template.Template{}, logger: log.NewNopLogger(),
}
_, err := email.auth("")
require.Error(t, err)
@@ -304,8 +486,9 @@
func TestEmailConfigMissingAuthParam(t *testing.T) {
+ conf := &config.EmailConfig{AuthUsername: "test"}
email := &Email{
- conf: &config.EmailConfig{}, tmpl: &template.Template{}, logger: log.NewNopLogger(),
+ conf: conf, tmpl: &template.Template{}, logger: log.NewNopLogger(),
}
_, err := email.auth("CRAM-MD5")
require.Error(t, err)
@@ -324,6 +507,15 @@
require.Equal(t, err.Error(), "missing password for PLAIN auth mechanism; missing password for LOGIN auth mechanism")
}
+func TestEmailNoUsernameStillOk(t *testing.T) {
+ email := &Email{
+ conf: &config.EmailConfig{}, tmpl: &template.Template{}, logger: log.NewNopLogger(),
+ }
+ a, err := email.auth("CRAM-MD5")
+ require.NoError(t, err)
+ require.Nil(t, a)
+}
+
func TestVictorOpsCustomFields(t *testing.T) {
logger := log.NewNopLogger()
tmpl := createTmpl(t)
@@ -371,3 +563,43 @@
// Verify that a custom field was added to the payload and templatized.
require.Equal(t, "message", m["Field_A"])
}
+
+func TestWechatRedactedURLOnInitialAuthentication(t *testing.T) {
+ ctx, u, fn := getContextWithCancelingURL()
+ defer fn()
+
+ secret := "secret_key"
+ notifier := NewWechat(
+ &config.WechatConfig{
+ APIURL: &config.URL{URL: u},
+ HTTPConfig: &commoncfg.HTTPClientConfig{},
+ CorpID: "corpid",
+ APISecret: config.Secret(secret),
+ },
+ createTmpl(t),
+ log.NewNopLogger(),
+ )
+
+ assertNotifyLeaksNoSecret(t, ctx, notifier, secret)
+}
+
+func TestWechatRedactedURLOnNotify(t *testing.T) {
+ secret, token := "secret", "token"
+ ctx, u, fn := getContextWithCancelingURL(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, `{"access_token":"%s"}`, token)
+ })
+ defer fn()
+
+ notifier := NewWechat(
+ &config.WechatConfig{
+ APIURL: &config.URL{URL: u},
+ HTTPConfig: &commoncfg.HTTPClientConfig{},
+ CorpID: "corpid",
+ APISecret: config.Secret(secret),
+ },
+ createTmpl(t),
+ log.NewNopLogger(),
+ )
+
+ assertNotifyLeaksNoSecret(t, ctx, notifier, secret, token)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/alertmanager-0.16.1/scripts/errcheck_excludes.txt new/alertmanager-0.16.2/scripts/errcheck_excludes.txt
--- old/alertmanager-0.16.1/scripts/errcheck_excludes.txt 2019-02-08 11:39:46.000000000 +0100
+++ new/alertmanager-0.16.2/scripts/errcheck_excludes.txt 2019-04-05 14:25:19.000000000 +0200
@@ -3,8 +3,8 @@
fmt.Fprintf
fmt.Fprintln
+// Exclude both vendored and un-vendored to cover both vendor mode and module mode.
(github.com/prometheus/alertmanager/vendor/github.com/go-kit/kit/log.Logger).Log
-// Allowed log levels are enforced via kingpin
-(*github.com/prometheus/alertmanager/vendor/github.com/prometheus/common/promlog.AllowedLevel).Set
+(github.com/go-kit/kit/log.Logger).Log
// Generated via go-swagger
(*github.com/prometheus/alertmanager/api/v2/restapi.Server).Shutdown