From 5ad26bf35cb0db117804c7fa38c80badc1c9e1f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giedrius=20Statkevi=C4=8Dius?= Date: Mon, 15 May 2023 11:45:06 +0300 Subject: [PATCH] config: allow exposing real secret value through marshal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are external projects out there that marshal/unmarshal the Prometheus config that has secrets. To get the real value currently such horrible workarounds are in place: https://github.com/tkestack/kvass/blob/master/pkg/sidecar/injector.go#L175-L214 Let's add a way to get the original values through the `Secret` type to avoid such things. Signed-off-by: Giedrius Statkevičius --- config/config.go | 11 +++++++++++ config/config_test.go | 32 ++++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/config/config.go b/config/config.go index 0b91f20d..3da4854d 100644 --- a/config/config.go +++ b/config/config.go @@ -27,8 +27,16 @@ const secretToken = "" // Secret special type for storing secrets. type Secret string +// MarshalSecretValue if set to true will expose Secret type +// through the marshal interfaces. Useful for outside projects +// that load and marshal the Prometheus config. +var MarshalSecretValue bool = false + // MarshalYAML implements the yaml.Marshaler interface for Secrets. func (s Secret) MarshalYAML() (interface{}, error) { + if MarshalSecretValue { + return string(s), nil + } if s != "" { return secretToken, nil } @@ -43,6 +51,9 @@ 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("") } diff --git a/config/config_test.go b/config/config_test.go index 1e031f50..51d23407 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -28,9 +28,11 @@ func TestJSONMarshalSecret(t *testing.T) { S Secret } for _, tc := range []struct { - desc string - data tmp - expected string + desc string + data tmp + expected string + trueValue bool + testYAML bool }{ { desc: "inhabited", @@ -39,6 +41,20 @@ func TestJSONMarshalSecret(t *testing.T) { data: tmp{"test"}, expected: "{\"S\":\"\\u003csecret\\u003e\"}", }, + { + desc: "true value in JSON", + data: tmp{"test"}, + expected: `{"S":"test"}`, + trueValue: true, + }, + { + desc: "true value in YAML", + data: tmp{"test"}, + expected: `s: test +`, + trueValue: true, + testYAML: true, + }, { desc: "empty", data: tmp{}, @@ -46,7 +62,15 @@ func TestJSONMarshalSecret(t *testing.T) { }, } { t.Run(tc.desc, func(t *testing.T) { - c, err := json.Marshal(tc.data) + MarshalSecretValue = tc.trueValue + + var marshalFN func(any) ([]byte, error) + if tc.testYAML { + marshalFN = yaml.Marshal + } else { + marshalFN = json.Marshal + } + c, err := marshalFN(tc.data) if err != nil { t.Fatal(err) }