Skip to content

Commit a8d4de6

Browse files
committed
feat: add config directive to pass wechat api secret via file
Ref: #2498 Signed-off-by: Christoph Maser <christoph.maser+github@gmail.com>
1 parent 29d491e commit a8d4de6

File tree

3 files changed

+64
-10
lines changed

3 files changed

+64
-10
lines changed

config/notifiers.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -636,15 +636,16 @@ type WechatConfig struct {
636636

637637
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
638638

639-
APISecret Secret `yaml:"api_secret,omitempty" json:"api_secret,omitempty"`
640-
CorpID string `yaml:"corp_id,omitempty" json:"corp_id,omitempty"`
641-
Message string `yaml:"message,omitempty" json:"message,omitempty"`
642-
APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"`
643-
ToUser string `yaml:"to_user,omitempty" json:"to_user,omitempty"`
644-
ToParty string `yaml:"to_party,omitempty" json:"to_party,omitempty"`
645-
ToTag string `yaml:"to_tag,omitempty" json:"to_tag,omitempty"`
646-
AgentID string `yaml:"agent_id,omitempty" json:"agent_id,omitempty"`
647-
MessageType string `yaml:"message_type,omitempty" json:"message_type,omitempty"`
639+
APISecret Secret `yaml:"api_secret,omitempty" json:"api_secret,omitempty"`
640+
APISecretFile string `yaml:"api_secret_file,omitempty" json:"api_secret_file,omitempty"`
641+
CorpID string `yaml:"corp_id,omitempty" json:"corp_id,omitempty"`
642+
Message string `yaml:"message,omitempty" json:"message,omitempty"`
643+
APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"`
644+
ToUser string `yaml:"to_user,omitempty" json:"to_user,omitempty"`
645+
ToParty string `yaml:"to_party,omitempty" json:"to_party,omitempty"`
646+
ToTag string `yaml:"to_tag,omitempty" json:"to_tag,omitempty"`
647+
AgentID string `yaml:"agent_id,omitempty" json:"agent_id,omitempty"`
648+
MessageType string `yaml:"message_type,omitempty" json:"message_type,omitempty"`
648649
}
649650

650651
const wechatValidTypesRe = `^(text|markdown)$`
@@ -667,6 +668,10 @@ func (c *WechatConfig) UnmarshalYAML(unmarshal func(any) error) error {
667668
return fmt.Errorf("weChat message type %q does not match valid options %s", c.MessageType, wechatValidTypesRe)
668669
}
669670

671+
if c.APISecret != "" && len(c.APISecretFile) > 0 {
672+
return errors.New("at most one of api_secret & api_secret_file must be configured")
673+
}
674+
670675
return nil
671676
}
672677

notify/wechat/wechat.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323
"log/slog"
2424
"net/http"
2525
"net/url"
26+
"os"
27+
"strings"
2628
"time"
2729

2830
commoncfg "github.com/prometheus/common/config"
@@ -97,7 +99,11 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
9799
// Refresh AccessToken over 2 hours
98100
if n.accessToken == "" || time.Since(n.accessTokenAt) > 2*time.Hour {
99101
parameters := url.Values{}
100-
parameters.Add("corpsecret", tmpl(string(n.conf.APISecret)))
102+
apiSecret, err := n.getApiSecret()
103+
if err != nil {
104+
return false, err
105+
}
106+
parameters.Add("corpsecret", tmpl(apiSecret))
101107
parameters.Add("corpid", tmpl(string(n.conf.CorpID)))
102108
if err != nil {
103109
return false, fmt.Errorf("templating error: %w", err)
@@ -194,3 +200,14 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
194200

195201
return false, errors.New(weResp.Error)
196202
}
203+
204+
func (n *Notifier) getApiSecret() (string, error) {
205+
if len(n.conf.APISecretFile) > 0 {
206+
content, err := os.ReadFile(n.conf.APISecretFile)
207+
if err != nil {
208+
return "", err
209+
}
210+
return strings.TrimSpace(string(content)), nil
211+
}
212+
return string(n.conf.APISecret), nil
213+
}

notify/wechat/wechat_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package wechat
1616
import (
1717
"fmt"
1818
"net/http"
19+
"os"
1920
"testing"
2021

2122
commoncfg "github.com/prometheus/common/config"
@@ -90,3 +91,34 @@ func TestWechatMessageTypeSelector(t *testing.T) {
9091

9192
test.AssertNotifyLeaksNoSecret(ctx, t, notifier, secret, token)
9293
}
94+
95+
func TestGetApiSecretFromSecret(t *testing.T) {
96+
n := &Notifier{conf: &config.WechatConfig{APISecret: config.Secret("shhh")}}
97+
s, err := n.getApiSecret()
98+
require.NoError(t, err)
99+
require.Equal(t, "shhh", s)
100+
}
101+
102+
func TestGetApiSecretFromFile(t *testing.T) {
103+
tmpFile, err := os.CreateTemp(t.TempDir(), "wechat-secret-*")
104+
require.NoError(t, err)
105+
secretContent := "file-secret\n"
106+
_, err = tmpFile.WriteString(secretContent)
107+
require.NoError(t, err)
108+
require.NoError(t, tmpFile.Close())
109+
110+
n := &Notifier{conf: &config.WechatConfig{APISecretFile: tmpFile.Name()}}
111+
s, err := n.getApiSecret()
112+
require.NoError(t, err)
113+
require.Equal(t, "file-secret", s)
114+
}
115+
116+
func TestGetApiSecretFromMissingFile(t *testing.T) {
117+
n := &Notifier{conf: &config.WechatConfig{APISecretFile: "/non/existent/wechat-secret.txt"}}
118+
s, err := n.getApiSecret()
119+
var pathErr *os.PathError
120+
require.ErrorAs(t, err, &pathErr)
121+
require.Equal(t, "/non/existent/wechat-secret.txt", pathErr.Path)
122+
require.ErrorIs(t, err, os.ErrNotExist)
123+
require.Empty(t, s)
124+
}

0 commit comments

Comments
 (0)