Skip to content

Commit 4d0fc05

Browse files
authored
Merge branch 'master' into sqlserver
2 parents ba7f666 + 35ff084 commit 4d0fc05

File tree

2 files changed

+128
-26
lines changed

2 files changed

+128
-26
lines changed

secretstores/local/file/filestore.go

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,27 @@ import (
1111
"fmt"
1212
"io/ioutil"
1313
"os"
14+
"reflect"
1415
"strconv"
1516
"strings"
1617

1718
"github.com/dapr/components-contrib/secretstores"
19+
"github.com/dapr/kit/config"
1820
"github.com/dapr/kit/logger"
1921
)
2022

2123
type localSecretStoreMetaData struct {
22-
SecretsFile string `json:"secretsFile"`
23-
NestedSeparator string `json:"nestedSeparator"`
24+
SecretsFile string `mapstructure:"secretsFile"`
25+
NestedSeparator string `mapstructure:"nestedSeparator"`
26+
MultiValued bool `mapstructure:"multiValued"`
2427
}
2528

2629
type localSecretStore struct {
2730
secretsFile string
2831
nestedSeparator string
2932
currenContext []string
3033
currentPath string
31-
secrets map[string]string
34+
secrets map[string]interface{}
3235
readLocalFileFn func(secretsFile string) (map[string]interface{}, error)
3336
logger logger.Logger
3437
}
@@ -57,14 +60,28 @@ func (j *localSecretStore) Init(metadata secretstores.Metadata) error {
5760
j.readLocalFileFn = j.readLocalFile
5861
}
5962

60-
j.secrets = map[string]string{}
61-
6263
jsonConfig, err := j.readLocalFileFn(meta.SecretsFile)
6364
if err != nil {
6465
return err
6566
}
6667

67-
j.visitJSONObject(jsonConfig)
68+
if meta.MultiValued {
69+
allSecrets := map[string]interface{}{}
70+
for k, v := range jsonConfig {
71+
switch v := v.(type) {
72+
case string:
73+
allSecrets[k] = v
74+
case map[string]interface{}:
75+
j.secrets = make(map[string]interface{})
76+
j.visitJSONObject(v)
77+
allSecrets[k] = j.secrets
78+
}
79+
}
80+
j.secrets = allSecrets
81+
} else {
82+
j.secrets = map[string]interface{}{}
83+
j.visitJSONObject(jsonConfig)
84+
}
6885

6986
return nil
7087
}
@@ -76,10 +93,25 @@ func (j *localSecretStore) GetSecret(req secretstores.GetSecretRequest) (secrets
7693
return secretstores.GetSecretResponse{}, fmt.Errorf("secret %s not found", req.Name)
7794
}
7895

96+
var data map[string]string
97+
switch v := secretValue.(type) {
98+
case string:
99+
data = map[string]string{
100+
req.Name: v,
101+
}
102+
case map[string]interface{}:
103+
data = make(map[string]string, len(v))
104+
for key, value := range v {
105+
data[key] = fmt.Sprint(value)
106+
}
107+
case map[string]string:
108+
data = v
109+
default:
110+
return secretstores.GetSecretResponse{}, fmt.Errorf("unexpected type %q for secret value", reflect.TypeOf(v))
111+
}
112+
79113
return secretstores.GetSecretResponse{
80-
Data: map[string]string{
81-
req.Name: secretValue,
82-
},
114+
Data: data,
83115
}, nil
84116
}
85117

@@ -88,7 +120,22 @@ func (j *localSecretStore) BulkGetSecret(req secretstores.BulkGetSecretRequest)
88120
r := map[string]map[string]string{}
89121

90122
for k, v := range j.secrets {
91-
r[k] = map[string]string{k: v}
123+
switch v := v.(type) {
124+
case string:
125+
r[k] = map[string]string{
126+
k: v,
127+
}
128+
case map[string]interface{}:
129+
data := make(map[string]string, len(v))
130+
for key, value := range v {
131+
data[key] = fmt.Sprint(value)
132+
}
133+
r[k] = data
134+
case map[string]string:
135+
r[k] = v
136+
default:
137+
return secretstores.BulkGetSecretResponse{}, fmt.Errorf("unexpected type %q for secret value", reflect.TypeOf(v))
138+
}
92139
}
93140

94141
return secretstores.BulkGetSecretResponse{
@@ -169,16 +216,12 @@ func (j *localSecretStore) combine(values []string) string {
169216
}
170217

171218
func (j *localSecretStore) getLocalSecretStoreMetadata(spec secretstores.Metadata) (*localSecretStoreMetaData, error) {
172-
b, err := json.Marshal(spec.Properties)
173-
if err != nil {
174-
return nil, err
175-
}
176-
177219
var meta localSecretStoreMetaData
178-
err = json.Unmarshal(b, &meta)
220+
err := config.Decode(spec.Properties, &meta)
179221
if err != nil {
180222
return nil, err
181223
}
224+
182225
if meta.SecretsFile == "" {
183226
return nil, fmt.Errorf("missing local secrets file in metadata")
184227
}

secretstores/local/file/filestore_test.go

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
package file
66

77
import (
8+
"encoding/json"
89
"fmt"
910
"testing"
1011

1112
"github.com/dapr/components-contrib/secretstores"
1213
"github.com/dapr/kit/logger"
1314
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/require"
1416
)
1517

1618
const secretValue = "secret"
@@ -25,16 +27,16 @@ func TestInit(t *testing.T) {
2527
}
2628
t.Run("Init with valid metadata", func(t *testing.T) {
2729
m.Properties = map[string]string{
28-
"SecretsFile": "a",
29-
"NestedSeparator": "a",
30+
"secretsFile": "a",
31+
"nestedSeparator": "a",
3032
}
3133
err := s.Init(m)
3234
assert.Nil(t, err)
3335
})
3436

3537
t.Run("Init with missing metadata", func(t *testing.T) {
3638
m.Properties = map[string]string{
37-
"Dummy": "a",
39+
"dummy": "a",
3840
}
3941
err := s.Init(m)
4042
assert.NotNil(t, err)
@@ -57,8 +59,8 @@ func TestSeparator(t *testing.T) {
5759
}
5860
t.Run("Init with custom separator", func(t *testing.T) {
5961
m.Properties = map[string]string{
60-
"SecretsFile": "a",
61-
"NestedSeparator": ".",
62+
"secretsFile": "a",
63+
"nestedSeparator": ".",
6264
}
6365
err := s.Init(m)
6466
assert.Nil(t, err)
@@ -74,7 +76,7 @@ func TestSeparator(t *testing.T) {
7476

7577
t.Run("Init with default separator", func(t *testing.T) {
7678
m.Properties = map[string]string{
77-
"SecretsFile": "a",
79+
"secretsFile": "a",
7880
}
7981
err := s.Init(m)
8082
assert.Nil(t, err)
@@ -92,8 +94,8 @@ func TestSeparator(t *testing.T) {
9294
func TestGetSecret(t *testing.T) {
9395
m := secretstores.Metadata{}
9496
m.Properties = map[string]string{
95-
"SecretsFile": "a",
96-
"NestedSeparator": "a",
97+
"secretsFile": "a",
98+
"nestedSeparator": "a",
9799
}
98100
s := localSecretStore{
99101
logger: logger.NewLogger("test"),
@@ -130,8 +132,8 @@ func TestGetSecret(t *testing.T) {
130132
func TestBulkGetSecret(t *testing.T) {
131133
m := secretstores.Metadata{}
132134
m.Properties = map[string]string{
133-
"SecretsFile": "a",
134-
"NestedSeparator": "a",
135+
"secretsFile": "a",
136+
"nestedSeparator": "a",
135137
}
136138
s := localSecretStore{
137139
logger: logger.NewLogger("test"),
@@ -151,3 +153,60 @@ func TestBulkGetSecret(t *testing.T) {
151153
assert.Equal(t, "secret", output.Data["secret"]["secret"])
152154
})
153155
}
156+
157+
func TestMultiValuedSecrets(t *testing.T) {
158+
m := secretstores.Metadata{}
159+
m.Properties = map[string]string{
160+
"secretsFile": "a",
161+
"multiValued": "true",
162+
}
163+
s := localSecretStore{
164+
logger: logger.NewLogger("test"),
165+
readLocalFileFn: func(secretsFile string) (map[string]interface{}, error) {
166+
//nolint:gosec
167+
secretsJSON := `
168+
{
169+
"parent": {
170+
"child1": "12345",
171+
"child2": {
172+
"child3": "67890",
173+
"child4": "00000"
174+
}
175+
}
176+
}
177+
`
178+
var secrets map[string]interface{}
179+
err := json.Unmarshal([]byte(secretsJSON), &secrets)
180+
181+
return secrets, err
182+
},
183+
}
184+
err := s.Init(m)
185+
require.NoError(t, err)
186+
187+
t.Run("successfully retrieve a single multi-valued secret", func(t *testing.T) {
188+
req := secretstores.GetSecretRequest{
189+
Name: "parent",
190+
}
191+
resp, err := s.GetSecret(req)
192+
require.NoError(t, err)
193+
assert.Equal(t, map[string]string{
194+
"child1": "12345",
195+
"child2:child3": "67890",
196+
"child2:child4": "00000",
197+
}, resp.Data)
198+
})
199+
200+
t.Run("successfully retrieve multi-valued secrets", func(t *testing.T) {
201+
req := secretstores.BulkGetSecretRequest{}
202+
resp, err := s.BulkGetSecret(req)
203+
require.NoError(t, err)
204+
assert.Equal(t, map[string]map[string]string{
205+
"parent": {
206+
"child1": "12345",
207+
"child2:child3": "67890",
208+
"child2:child4": "00000",
209+
},
210+
}, resp.Data)
211+
})
212+
}

0 commit comments

Comments
 (0)