Skip to content

Commit 0975d17

Browse files
committed
Improve capabilities of planned data redaction
Support more complex data shapes in terraform plans.
1 parent 2b2d5dd commit 0975d17

File tree

4 files changed

+136
-28
lines changed

4 files changed

+136
-28
lines changed

cmd/submitplan.go

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ type TfData struct {
8181
}
8282

8383
// maskAllData masks every entry in attributes as redacted
84-
func maskAllData(attributes map[string]interface{}) map[string]interface{} {
84+
func maskAllData(attributes map[string]any) map[string]any {
8585
for k, v := range attributes {
86-
if mv, ok := v.(map[string]interface{}); ok {
86+
if mv, ok := v.(map[string]any); ok {
8787
attributes[k] = maskAllData(mv)
8888
} else {
8989
attributes[k] = "REDACTED"
@@ -93,35 +93,50 @@ func maskAllData(attributes map[string]interface{}) map[string]interface{} {
9393
}
9494

9595
// maskSensitiveData masks every entry in attributes that is set to true in sensitive. returns the redacted attributes
96-
func maskSensitiveData(attributes, sensitive map[string]interface{}) map[string]interface{} {
96+
func maskSensitiveData(attributes, sensitive map[string]any) map[string]any {
9797
for k, s := range sensitive {
98-
log.Debugf("checking %v", k)
99-
if mv, ok := s.(map[string]interface{}); ok {
100-
if sub, ok := attributes[k].(map[string]interface{}); ok {
98+
log.Debugf("checking %v: %v", k, s)
99+
if mv, ok := s.(map[string]any); ok {
100+
if sub, ok := attributes[k].(map[string]any); ok {
101101
attributes[k] = maskSensitiveData(sub, mv)
102102
}
103+
} else if arr, ok := s.([]any); ok {
104+
if sub, ok := attributes[k].([]any); ok {
105+
if len(arr) != len(sub) {
106+
attributes[k] = "REDACTED (len mismatch)"
107+
continue
108+
}
109+
for i, v := range arr {
110+
if v == true {
111+
sub[i] = "REDACTED"
112+
}
113+
}
114+
attributes[k] = sub
115+
}
103116
} else {
104-
attributes[k] = "REDACTED"
117+
if _, ok := attributes[k]; ok {
118+
attributes[k] = "REDACTED"
119+
}
105120
}
106121
}
107122
return attributes
108123
}
109124

110125
func itemAttributesFromResourceChangeData(attributesMsg, sensitiveMsg json.RawMessage) (*sdp.ItemAttributes, error) {
111-
var attributes map[string]interface{}
126+
var attributes map[string]any
112127
err := json.Unmarshal(attributesMsg, &attributes)
113128
if err != nil {
114129
return nil, fmt.Errorf("failed to parse attributes: %w", err)
115130
}
116131

117-
// sensitiveMsg can be a bool or a map[string]interface{}
132+
// sensitiveMsg can be a bool or a map[string]any
118133
var isSensitive bool
119134
err = json.Unmarshal(sensitiveMsg, &isSensitive)
120135
if err == nil && isSensitive {
121136
attributes = maskAllData(attributes)
122137
} else if err != nil {
123138
// only try parsing as map if parsing as bool failed
124-
var sensitive map[string]interface{}
139+
var sensitive map[string]any
125140
err = json.Unmarshal(sensitiveMsg, &sensitive)
126141
if err != nil {
127142
return nil, fmt.Errorf("failed to parse sensitive: %w", err)
@@ -164,7 +179,7 @@ func itemDiffFromResourceChange(resourceChange ResourceChange) (*sdp.ItemDiff, e
164179
}
165180

166181
if beforeAttributes != nil {
167-
result.Before = &sdp.Item{ // DODO: check for empty before/after attributes and set to nil
182+
result.Before = &sdp.Item{
168183
Type: resourceChange.Type,
169184
UniqueAttribute: "terraform_address",
170185
Attributes: beforeAttributes,
@@ -326,7 +341,7 @@ func mappedItemDiffsFromPlan(ctx context.Context, fileName string, lf log.Fields
326341
}
327342

328343
// Create the map that variables will pull data from
329-
dataMap := make(map[string]interface{})
344+
dataMap := make(map[string]any)
330345

331346
// Populate resource values
332347
dataMap["values"] = currentResource.AttributeValues

cmd/submitplan_test.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/overmindtech/sdp-go"
88
"github.com/sirupsen/logrus"
9+
"github.com/stretchr/testify/require"
910
)
1011

1112
func TestMappedItemDiffsFromPlan(t *testing.T) {
@@ -136,3 +137,107 @@ func TestMappedItemDiffsFromPlan(t *testing.T) {
136137
t.Errorf("Expected aws_iam_policy query query to be 'arn:aws:iam::123456789012:policy/test-alb-ingress', got '%v'", aws_iam_policy.MappingQuery.Query)
137138
}
138139
}
140+
141+
// note that these tests need to allocate the input map for every test as
142+
// maskSensitiveData mutates its inputs
143+
func TestMaskSensitiveData(t *testing.T) {
144+
t.Parallel()
145+
146+
t.Run("empty", func(t *testing.T) {
147+
t.Parallel()
148+
got := maskSensitiveData(map[string]any{}, map[string]any{})
149+
require.Equal(t, got, map[string]any{})
150+
})
151+
152+
t.Run("easy", func(t *testing.T) {
153+
t.Parallel()
154+
require.Equal(t,
155+
map[string]any{
156+
"foo": "bar",
157+
},
158+
maskSensitiveData(
159+
map[string]any{
160+
"foo": "bar",
161+
},
162+
map[string]any{}))
163+
164+
require.Equal(t,
165+
map[string]any{
166+
"foo": "REDACTED",
167+
},
168+
maskSensitiveData(
169+
map[string]any{
170+
"foo": "bar",
171+
},
172+
map[string]any{"foo": true}))
173+
174+
})
175+
176+
t.Run("deep", func(t *testing.T) {
177+
t.Parallel()
178+
require.Equal(t,
179+
map[string]any{
180+
"foo": map[string]any{"key": "bar"},
181+
},
182+
maskSensitiveData(
183+
map[string]any{
184+
"foo": map[string]any{"key": "bar"},
185+
},
186+
map[string]any{}))
187+
188+
require.Equal(t,
189+
map[string]any{
190+
"foo": "REDACTED",
191+
},
192+
maskSensitiveData(
193+
map[string]any{
194+
"foo": map[string]any{"key": "bar"},
195+
},
196+
map[string]any{"foo": true}))
197+
198+
require.Equal(t,
199+
map[string]any{
200+
"foo": map[string]any{"key": "REDACTED"},
201+
},
202+
maskSensitiveData(
203+
map[string]any{
204+
"foo": map[string]any{"key": "bar"},
205+
},
206+
map[string]any{"foo": map[string]any{"key": true}}))
207+
208+
})
209+
210+
t.Run("arrays", func(t *testing.T) {
211+
t.Parallel()
212+
require.Equal(t,
213+
map[string]any{
214+
"foo": []any{"one", "two"},
215+
},
216+
maskSensitiveData(
217+
map[string]any{
218+
"foo": []any{"one", "two"},
219+
},
220+
map[string]any{}))
221+
222+
require.Equal(t,
223+
map[string]any{
224+
"foo": "REDACTED",
225+
},
226+
maskSensitiveData(
227+
map[string]any{
228+
"foo": []any{"one", "two"},
229+
},
230+
map[string]any{"foo": true}))
231+
232+
require.Equal(t,
233+
map[string]any{
234+
"foo": []any{"one", "REDACTED"},
235+
},
236+
maskSensitiveData(
237+
map[string]any{
238+
"foo": []any{"one", "two"},
239+
},
240+
map[string]any{"foo": []any{false, true}}))
241+
242+
})
243+
}

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ require (
1010
github.com/mattn/go-isatty v0.0.20
1111
github.com/overmindtech/sdp-go v0.57.0
1212
github.com/sirupsen/logrus v1.9.3
13-
github.com/sourcegraph/conc v0.3.0
1413
github.com/spf13/cobra v1.8.0
1514
github.com/spf13/viper v1.17.0
15+
github.com/stretchr/testify v1.8.4
1616
github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31
1717
github.com/uptrace/opentelemetry-go-extra/otellogrus v0.2.3
1818
github.com/xiam/dig v0.0.0-20191116195832-893b5fb5093b
@@ -32,6 +32,7 @@ require (
3232
github.com/auth0/go-jwt-middleware/v2 v2.1.0 // indirect
3333
github.com/aws/aws-sdk-go v1.45.16 // indirect
3434
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
35+
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3536
github.com/felixge/httpsnoop v1.0.3 // indirect
3637
github.com/fsnotify/fsnotify v1.6.0 // indirect
3738
github.com/go-logr/logr v1.2.4 // indirect
@@ -50,9 +51,11 @@ require (
5051
github.com/nats-io/nuid v1.0.1 // indirect
5152
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
5253
github.com/pkg/errors v0.9.1 // indirect
54+
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
5355
github.com/rivo/uniseg v0.4.4 // indirect
5456
github.com/sagikazarmark/locafero v0.3.0 // indirect
5557
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
58+
github.com/sourcegraph/conc v0.3.0 // indirect
5659
github.com/spf13/afero v1.10.0 // indirect
5760
github.com/spf13/cast v1.5.1 // indirect
5861
github.com/spf13/pflag v1.0.5 // indirect

go.sum

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
5454
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
5555
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
5656
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
57-
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
5857
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
5958
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6059
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -192,8 +191,6 @@ github.com/nats-io/nkeys v0.4.6 h1:IzVe95ru2CT6ta874rt9saQRkWfe2nFj1NtvYSLqMzY=
192191
github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts=
193192
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
194193
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
195-
github.com/overmindtech/sdp-go v0.56.0 h1:1VFF6kulsNIVVctBClZbeZxOsHKRQDPzfZPVmwcWGSo=
196-
github.com/overmindtech/sdp-go v0.56.0/go.mod h1:WZ/CsRATgtF0KZpgrlJdzLieBO3Gk9mk5XcdrSVOkbQ=
197194
github.com/overmindtech/sdp-go v0.57.0 h1:hUqBij/gmc11TaQF4OOKj15kZH6SZJsObQgeCah0vRc=
198195
github.com/overmindtech/sdp-go v0.57.0/go.mod h1:G01shsRPrtJBMQb2HizIG1BIst7jG8Q6BZ+G8/9YPHM=
199196
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
@@ -227,8 +224,6 @@ github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
227224
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
228225
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
229226
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
230-
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
231-
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
232227
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
233228
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
234229
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -302,8 +297,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
302297
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
303298
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
304299
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
305-
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
306-
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
307300
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
308301
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
309302
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -376,8 +369,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
376369
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
377370
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
378371
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
379-
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
380-
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
381372
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
382373
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
383374
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -389,8 +380,6 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
389380
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
390381
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
391382
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
392-
golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY=
393-
golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0=
394383
golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
395384
golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
396385
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -445,8 +434,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
445434
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
446435
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
447436
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
448-
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
449-
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
450437
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
451438
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
452439
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -461,8 +448,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
461448
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
462449
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
463450
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
464-
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
465-
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
466451
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
467452
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
468453
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

0 commit comments

Comments
 (0)