Skip to content

Commit

Permalink
update config to use MarshalSecretValue
Browse files Browse the repository at this point in the history
Signed-off-by: Walther Lee <[email protected]>
  • Loading branch information
Walther Lee committed Dec 6, 2024
1 parent 0d28327 commit 4f10742
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 2 deletions.
26 changes: 26 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ const secretToken = "<secret>"

var secretTokenJSON string

// MarshalSecretValue if set to true will expose Secret type
// through the marshal interfaces. Useful for outside projects
// that load and marshal the Alertmanager config.
var MarshalSecretValue bool = commoncfg.MarshalSecretValue

func init() {
b, err := json.Marshal(secretToken)
if err != nil {
Expand All @@ -52,6 +57,9 @@ type Secret string

// MarshalYAML implements the yaml.Marshaler interface for Secret.
func (s Secret) MarshalYAML() (interface{}, error) {
if MarshalSecretValue {
return string(s), nil
}
if s != "" {
return secretToken, nil
}
Expand All @@ -66,6 +74,12 @@ func (s *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error {

// MarshalJSON implements the json.Marshaler interface for Secret.
func (s Secret) MarshalJSON() ([]byte, error) {
if MarshalSecretValue {
return json.Marshal(string(s))
}
if len(s) == 0 {
return json.Marshal("")
}
return json.Marshal(secretToken)
}

Expand Down Expand Up @@ -130,6 +144,9 @@ type SecretURL URL
// MarshalYAML implements the yaml.Marshaler interface for SecretURL.
func (s SecretURL) MarshalYAML() (interface{}, error) {
if s.URL != nil {
if MarshalSecretValue {
return s.URL.String(), nil
}
return secretToken, nil
}
return nil, nil
Expand All @@ -153,6 +170,12 @@ func (s *SecretURL) UnmarshalYAML(unmarshal func(interface{}) error) error {

// MarshalJSON implements the json.Marshaler interface for SecretURL.
func (s SecretURL) MarshalJSON() ([]byte, error) {
if s.URL == nil {
return json.Marshal("")
}
if MarshalSecretValue {
return json.Marshal(s.URL.String())
}
return json.Marshal(secretToken)
}

Expand All @@ -167,6 +190,9 @@ func (s *SecretURL) UnmarshalJSON(data []byte) error {
}
// Redact the secret URL in case of errors
if err := json.Unmarshal(data, (*URL)(s)); err != nil {
if MarshalSecretValue {
return err
}
return errors.New(strings.ReplaceAll(err.Error(), string(data), "[REDACTED]"))
}

Expand Down
66 changes: 64 additions & 2 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,22 @@ func TestHideConfigSecrets(t *testing.T) {
}
}

func TestShowMarshalSecretValues(t *testing.T) {
MarshalSecretValue = true
defer func() { MarshalSecretValue = false }()

c, err := LoadFile("testdata/conf.good.yml")
if err != nil {
t.Fatalf("Error parsing %s: %s", "testdata/conf.good.yml", err)
}

// String method must reveal authentication credentials.
s := c.String()
if strings.Count(s, "<secret>") > 0 || !strings.Contains(s, "mysecret") {
t.Fatal("config's String method must reveal authentication credentials when MarshalSecretValue = true.")
}
}

func TestJSONMarshal(t *testing.T) {
c, err := LoadFile("testdata/conf.good.yml")
if err != nil {
Expand All @@ -533,7 +549,7 @@ func TestJSONMarshal(t *testing.T) {
}
}

func TestJSONMarshalSecret(t *testing.T) {
func TestJSONMarshalHideSecret(t *testing.T) {
test := struct {
S Secret
}{
Expand All @@ -550,7 +566,24 @@ func TestJSONMarshalSecret(t *testing.T) {
require.Equal(t, "{\"S\":\"\\u003csecret\\u003e\"}", string(c), "Secret not properly elided.")
}

func TestMarshalSecretURL(t *testing.T) {
func TestJSONMarshalShowSecret(t *testing.T) {
MarshalSecretValue = true
defer func() { MarshalSecretValue = false }()

test := struct {
S Secret
}{
S: Secret("test"),
}

c, err := json.Marshal(test)
if err != nil {
t.Fatal(err)
}
require.Equal(t, "{\"S\":\"test\"}", string(c), "config's String method must reveal authentication credentials when MarshalSecretValue = true.")
}

func TestJSONMarshalHideSecretURL(t *testing.T) {
urlp, err := url.Parse("http://example.com/")
if err != nil {
t.Fatal(err)
Expand Down Expand Up @@ -584,6 +617,23 @@ func TestMarshalSecretURL(t *testing.T) {
}
}

func TestJSONMarshalShowSecretURL(t *testing.T) {
MarshalSecretValue = true
defer func() { MarshalSecretValue = false }()

urlp, err := url.Parse("http://example.com/")
if err != nil {
t.Fatal(err)
}
u := &SecretURL{urlp}

c, err := json.Marshal(u)
if err != nil {
t.Fatal(err)
}
require.Equal(t, "\"http://example.com/\"", string(c), "config's String method must reveal authentication credentials when MarshalSecretValue = true.")
}

func TestUnmarshalSecretURL(t *testing.T) {
b := []byte(`"http://example.com/se cret"`)
var u SecretURL
Expand Down Expand Up @@ -611,6 +661,18 @@ func TestHideSecretURL(t *testing.T) {
require.NotContains(t, err.Error(), "wrongurl")
}

func TestShowMarshalSecretURL(t *testing.T) {
MarshalSecretValue = true
defer func() { MarshalSecretValue = false }()

b := []byte(`"://wrongurl/"`)
var u SecretURL

err := json.Unmarshal(b, &u)
require.Error(t, err)
require.Contains(t, err.Error(), "wrongurl")
}

func TestMarshalURL(t *testing.T) {
for name, tc := range map[string]struct {
input *URL
Expand Down

0 comments on commit 4f10742

Please sign in to comment.