Skip to content

Commit a11bf9f

Browse files
committed
fix: only loading required values when using --dir limit
1 parent c06eb6f commit a11bf9f

5 files changed

Lines changed: 116 additions & 54 deletions

File tree

internal/secret/loader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func LoadLocalSecretsLimited(targetTypeFilter SecretTargetType, directoryLimit s
5252
)
5353
for _, secretFileName := range secretFileNames {
5454
bar.Add(1)
55-
secret, err := FromPath(secretFileName)
55+
secret, err := FromPath(secretFileName, directoryLimit)
5656
if err != nil {
5757
bar.Finish()
5858
return nil, err

internal/secret/secret.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type Secret struct {
4747
}
4848

4949
type SecretTargetType string
50+
5051
var SecretTargetTypeVault SecretTargetType = "vault"
5152
var SecretTargetTypeKubernetes SecretTargetType = "k8s"
5253
var SecretTargetTypeAll SecretTargetType = "all"
@@ -57,15 +58,15 @@ type SecretFile struct {
5758
Name string `yaml:"name,omitempty"`
5859
Namespace string `yaml:"namespace" default:"default"`
5960
Type string `yaml:"type" default:"Opaque"`
60-
Data map[string]string `yaml:"data"`
61+
Data map[string]string `yaml:"data"`
6162
ID string `yaml:"id,omitempty"`
6263
}
6364

6465
type TemplateData struct {
6566
Values map[interface{}]interface{}
6667
}
6768

68-
func (s *Secret) Load() error {
69+
func (s *Secret) Load(directoryLimit string) error {
6970
if s.Path == "" {
7071
return errors.New("secret path is empty")
7172
}
@@ -78,7 +79,7 @@ func (s *Secret) Load() error {
7879

7980
// execute templating on the secret file data
8081
data := TemplateData{
81-
Values: templating.GetValuesForPath(s.Path),
82+
Values: templating.GetValuesForPath(s.Path, directoryLimit),
8283
}
8384
stringData := string(decryptedFileContent)
8485
tmpl, err := template.New(s.Path).Parse(stringData)
@@ -103,7 +104,7 @@ func (s *Secret) Load() error {
103104
yaml.UnmarshalStrict(s.BinaryData, &secretFile)
104105

105106
s.TargetType = secretFile.TargetType
106-
107+
107108
if secretFile.Target != "" {
108109
s.Target = secretFile.Target
109110
} else {
@@ -128,13 +129,13 @@ func (s *Secret) Load() error {
128129
} else {
129130
s.Type = "Opaque"
130131
}
131-
132+
132133
s.Data = secretFile.Data
133134

134135
if util.GetCliContext().Bool("print") {
135136
s.PrettyPrint()
136137
}
137-
138+
138139
return nil
139140
}
140141

@@ -160,16 +161,15 @@ func (s *Secret) PrettyPrint() {
160161
}
161162
}
162163

163-
func FromPath(path string) (*Secret, error) {
164-
s := Secret {
164+
func FromPath(path string, directoryLimit string) (*Secret, error) {
165+
s := Secret{
165166
Path: path,
166167
}
167168

168-
err := s.Load()
169+
err := s.Load(directoryLimit)
169170
if err != nil {
170171
return nil, err
171172
}
172173

173174
return &s, nil
174175
}
175-

internal/secret/secret_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ func TestLoadSecret1(t *testing.T) {
1212
secret := Secret {
1313
Path: f,
1414
}
15-
err := secret.Load()
15+
err := secret.Load("")
1616

1717
if err != nil {
1818
t.Error(err)
@@ -31,7 +31,7 @@ func TestLoadSecret2(t *testing.T) {
3131
secret := Secret {
3232
Path: f,
3333
}
34-
err := secret.Load()
34+
err := secret.Load("")
3535

3636
if err != nil {
3737
t.Error(err)

internal/templating/templating.go

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,33 @@ import (
1414
)
1515

1616
type TemplateValues []*TemplateValuesPath
17+
1718
var templateValues = TemplateValues{}
1819

1920
type TemplateValuesPath struct {
20-
Path string
21-
Values map[interface{}]interface{}
22-
MergedValues map[interface{}]interface{}
21+
Path string
22+
Values map[interface{}]interface{}
23+
MergedValues map[interface{}]interface{}
2324
}
2425

2526
var loaded = false
26-
func LoadValues() error {
27+
28+
func LoadValues(directoryLimit string) error {
2729
log.Trace("Loading values files")
2830
secretFiles, err := util.GetSecretFiles()
2931
if err != nil {
3032
return err
3133
}
3234
var valuesFiles []string
33-
for _, secretFile := range secretFiles {
34-
if strings.HasSuffix(secretFile, "values.gitops.secret.enc.yaml") || strings.HasSuffix(secretFile, "values.gitops.secret.enc.yml") {
35-
valuesFiles = append(valuesFiles, secretFile)
35+
for _, secretFileName := range secretFiles {
36+
if !strings.HasSuffix(secretFileName, "values.gitops.secret.enc.yaml") && !strings.HasSuffix(secretFileName, "values.gitops.secret.enc.yml") {
37+
continue
38+
}
39+
if !valuesFileApplicable(secretFileName, directoryLimit) {
40+
log.Trace("Skipping values file due to directory filter: ", secretFileName)
41+
continue
3642
}
43+
valuesFiles = append(valuesFiles, secretFileName)
3744
}
3845

3946
for _, valuesFile := range valuesFiles {
@@ -46,8 +53,8 @@ func LoadValues() error {
4653
var values map[interface{}]interface{}
4754
yaml.UnmarshalStrict(decryptedFileContent, &values)
4855
templateValues = append(templateValues, &TemplateValuesPath{
49-
Path: fmt.Sprintf("%s/", filepath.ToSlash(filepath.Dir(valuesFile))),
50-
Values: values,
56+
Path: fmt.Sprintf("%s/", filepath.ToSlash(filepath.Dir(valuesFile))),
57+
Values: values,
5158
})
5259
}
5360

@@ -59,20 +66,20 @@ func LoadValues() error {
5966
func mergeMaps(a, b map[interface{}]interface{}) map[interface{}]interface{} {
6067
out := make(map[interface{}]interface{}, len(a))
6168
for k, v := range a {
62-
out[k] = v
69+
out[k] = v
6370
}
6471
for k, v := range b {
65-
// If you use map[string]interface{}, ok is always false here.
66-
// Because yaml.Unmarshal will give you map[interface{}]interface{}.
67-
if v, ok := v.(map[interface{}]interface{}); ok {
68-
if bv, ok := out[k]; ok {
69-
if bv, ok := bv.(map[interface{}]interface{}); ok {
70-
out[k] = mergeMaps(bv, v)
71-
continue
72-
}
73-
}
72+
// If you use map[string]interface{}, ok is always false here.
73+
// Because yaml.Unmarshal will give you map[interface{}]interface{}.
74+
if v, ok := v.(map[interface{}]interface{}); ok {
75+
if bv, ok := out[k]; ok {
76+
if bv, ok := bv.(map[interface{}]interface{}); ok {
77+
out[k] = mergeMaps(bv, v)
78+
continue
79+
}
7480
}
75-
out[k] = v
81+
}
82+
out[k] = v
7683
}
7784
return out
7885
}
@@ -100,9 +107,9 @@ func (t TemplateValues) merge() {
100107
}
101108
}
102109

103-
func GetValuesForPath(path string) map[interface{}]interface{} {
110+
func GetValuesForPath(path string, directoryLimit string) map[interface{}]interface{} {
104111
if !loaded {
105-
err := LoadValues()
112+
err := LoadValues(directoryLimit)
106113
if err != nil {
107114
log.Panic(err)
108115
}
@@ -125,4 +132,33 @@ func GetValuesForPath(path string) map[interface{}]interface{} {
125132
}
126133

127134
return values
128-
}
135+
}
136+
137+
func valuesFileApplicable(secretFile, directoryLimit string) bool {
138+
secretFile = filepath.Clean(secretFile)
139+
directoryLimit = filepath.Clean(directoryLimit)
140+
141+
if directoryLimit == "" {
142+
return true
143+
}
144+
145+
secretFileParentDir := filepath.Dir(secretFile)
146+
secretFileDirectoryElements := strings.Split(secretFileParentDir, string(filepath.Separator))
147+
directoryLimitElements := strings.Split(directoryLimit, string(filepath.Separator))
148+
149+
if len(secretFileDirectoryElements) <= len(directoryLimitElements) {
150+
for i, secretFileDirectoryElement := range secretFileDirectoryElements {
151+
if secretFileDirectoryElement != directoryLimitElements[i] {
152+
return false
153+
}
154+
}
155+
} else {
156+
for i, directoryLimitElement := range directoryLimitElements {
157+
if directoryLimitElement != secretFileDirectoryElements[i] {
158+
return false
159+
}
160+
}
161+
}
162+
163+
return true
164+
}

internal/templating/templating_test.go

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@ import (
99

1010
func TestMapMerge1(t *testing.T) {
1111
a := map[interface{}]interface{}{
12-
"foo": "bar",
12+
"foo": "bar",
1313
"fizz": "buzz",
1414
}
1515
b := map[interface{}]interface{}{
1616
"fizz": "fizz",
1717
}
1818
c := map[interface{}]interface{}{
19-
"foo": "bar",
19+
"foo": "bar",
2020
"fizz": "fizz",
2121
}
2222
d := mergeMaps(a, b)
23-
assert.Equal(t, c, d, "Maps should be equal")
23+
assert.Equal(t, c, d, "Maps should be equal")
2424
}
2525

2626
func TestMapMerge2(t *testing.T) {
@@ -39,7 +39,7 @@ func TestMapMerge2(t *testing.T) {
3939
"d": "4",
4040
}
4141
d := mergeMaps(a, b)
42-
assert.Equal(t, c, d, "Maps should be equal")
42+
assert.Equal(t, c, d, "Maps should be equal")
4343
}
4444

4545
func TestMapMerge3(t *testing.T) {
@@ -55,7 +55,7 @@ func TestMapMerge3(t *testing.T) {
5555
"b": 42,
5656
}
5757
d := mergeMaps(a, b)
58-
assert.Equal(t, c, d, "Maps should be equal")
58+
assert.Equal(t, c, d, "Maps should be equal")
5959
}
6060

6161
func TestMapMerge4(t *testing.T) {
@@ -71,7 +71,7 @@ func TestMapMerge4(t *testing.T) {
7171
"b": []interface{}{"2", "3"},
7272
}
7373
d := mergeMaps(a, b)
74-
assert.Equal(t, c, d, "Maps should be equal")
74+
assert.Equal(t, c, d, "Maps should be equal")
7575
}
7676

7777
func TestTemplateValuesMerge(t *testing.T) {
@@ -159,31 +159,57 @@ func TestTemplateValuesMerge(t *testing.T) {
159159
assert.Equal(t, expectedMergedTemplateValues, templateValues, "TemplateValues should be equal")
160160
}
161161

162-
163162
func TestValuesFileLoading(t *testing.T) {
164163
c := util.GetDummyCliContext()
165164
util.SetCliContext(c)
166165
util.ComputeRootDir(c)
167-
168-
LoadValues()
169-
166+
167+
LoadValues("")
168+
170169
valuesSet1 := map[interface{}]interface{}{
171-
"namespace": "gitops-dev",
172-
"stage": "dev",
170+
"namespace": "gitops-dev",
171+
"stage": "dev",
173172
"databaseUsername": "my-very-strong-username",
174173
"databasePassword": "my-very-strong-password",
175174
}
176175

177-
mergedValues1 := GetValuesForPath("test_assets/implicit-name.gitops.secret.enc.yml")
176+
mergedValues1 := GetValuesForPath("test_assets/implicit-name.gitops.secret.enc.yml", "")
178177
assert.Equal(t, valuesSet1, mergedValues1, "Values should be equal")
179178

180179
valuesSet2 := map[interface{}]interface{}{
181-
"namespace": "gitops-dev",
182-
"stage": "sub-dev",
180+
"namespace": "gitops-dev",
181+
"stage": "sub-dev",
183182
"databaseUsername": "my-very-strong-username",
184183
"databasePassword": "my-very-strong-password",
185-
"key": "fooo",
184+
"key": "fooo",
186185
}
187-
mergedValues2 := GetValuesForPath("test_assets/subdirectory/subdir-secret.gitops.secret.enc.yml")
186+
mergedValues2 := GetValuesForPath("test_assets/subdirectory/subdir-secret.gitops.secret.enc.yml", "")
188187
assert.Equal(t, valuesSet2, mergedValues2, "Values should be equal")
189-
}
188+
}
189+
190+
func TestIsInParentPath(t *testing.T) {
191+
tests := []struct {
192+
name string
193+
path1 string
194+
path2 string
195+
expected bool
196+
}{
197+
{"Direct Parent", "a/b/c.txt", "a/b/d/", true},
198+
{"Grandparent", "a/b/c.txt", "a/b/d/e/", true},
199+
{"Not a Parent", "a/b/c.txt", "f/g/h/", false},
200+
{"Same Directory", "a/b/c.txt", "a/b/", true},
201+
{"Root Directory", "c.txt", "/", false},
202+
{"Path2 is Parent", "a/b/c/d.txt", "a/b/c", true},
203+
{"Nested under filter", "a/b/c/d.txt", "a/", true},
204+
}
205+
206+
for _, tt := range tests {
207+
t.Run(tt.name, func(t *testing.T) {
208+
result := valuesFileApplicable(tt.path1, tt.path2)
209+
210+
if result != tt.expected {
211+
t.Errorf("isInParentPath(%q, %q) = %v; expected %v", tt.path1, tt.path2, result, tt.expected)
212+
}
213+
})
214+
}
215+
}

0 commit comments

Comments
 (0)