Skip to content

Commit

Permalink
Move hide logic to a generic func
Browse files Browse the repository at this point in the history
Signed-off-by: Siddhesh Ghadi <sghadi1203@gmail.com>
  • Loading branch information
svghadi committed Sep 19, 2024
1 parent acd76f2 commit 6395c89
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 74 deletions.
106 changes: 46 additions & 60 deletions pkg/diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -972,7 +972,7 @@ func CreateTwoWayMergePatch(orig, new, dataStruct interface{}) ([]byte, bool, er
// HideSecretData replaces secret data & optional annotations values in specified target, live secrets and in last applied configuration of live secret with stars. Also preserves differences between
// target, live and last applied config values. E.g. if all three are equal the values would be replaced with same number of stars. If all the are different then number of stars
// in replacement should be different.
func HideSecretData(target *unstructured.Unstructured, live *unstructured.Unstructured, hideAnnots ...string) (*unstructured.Unstructured, *unstructured.Unstructured, error) {
func HideSecretData(target *unstructured.Unstructured, live *unstructured.Unstructured, hideAnnots map[string]bool) (*unstructured.Unstructured, *unstructured.Unstructured, error) {
var orig *unstructured.Unstructured
if live != nil {
orig, _ = GetLastAppliedConfigAnnotation(live)
Expand All @@ -995,7 +995,36 @@ func HideSecretData(target *unstructured.Unstructured, live *unstructured.Unstru
}
}

var err error
// hide data
target, live, orig, err = hide(target, live, orig, keys, "data")
if err != nil {
return nil, nil, err
}

// hide annotations
target, live, orig, err = hide(target, live, orig, hideAnnots, "metadata", "annotations")
if err != nil {
return nil, nil, err
}

// hide last-applied-config annotation
if live != nil && orig != nil {
annotations := live.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
lastAppliedData, err := json.Marshal(orig)
if err != nil {
return nil, nil, fmt.Errorf("error marshaling json: %s", err)
}
annotations[corev1.LastAppliedConfigAnnotation] = string(lastAppliedData)
live.SetAnnotations(annotations)
}
return target, live, nil
}

func hide(target, live, orig *unstructured.Unstructured, keys map[string]bool, fields ...string) (*unstructured.Unstructured, *unstructured.Unstructured, *unstructured.Unstructured, error) {
for k := range keys {
// we use "+" rather than the more common "*"
nextReplacement := "++++++++"
Expand All @@ -1005,16 +1034,14 @@ func HideSecretData(target *unstructured.Unstructured, live *unstructured.Unstru
if obj != nil {
// handles an edge case when secret data has nil value
// https://github.com/argoproj/argo-cd/issues/5584
dataValue, ok := obj.Object["data"]
if ok {
if dataValue == nil {
continue
}
dataValue, ok, _ := unstructured.NestedFieldCopy(obj.Object, fields...)
if !ok || dataValue == nil {
continue
}
var err error
data, _, err = unstructured.NestedMap(obj.Object, "data")
data, _, err = unstructured.NestedMap(obj.Object, fields...)
if err != nil {
return nil, nil, fmt.Errorf("unstructured.NestedMap error: %s", err)
return nil, nil, nil, fmt.Errorf("unstructured.NestedMap error: %s", err)
}
}
if data == nil {
Expand All @@ -1032,62 +1059,13 @@ func HideSecretData(target *unstructured.Unstructured, live *unstructured.Unstru
valToReplacement[val] = replacement
}
data[k] = replacement
err := unstructured.SetNestedField(obj.Object, data, "data")
if err != nil {
return nil, nil, fmt.Errorf("unstructured.SetNestedField error: %s", err)
}
}
}

// hide annotations
for _, k := range hideAnnots {
nextReplacement := "++++++++"
valToReplacement := make(map[string]string)
for _, obj := range []*unstructured.Unstructured{target, live, orig} {
var annots map[string]interface{}
var err error
if obj != nil {
annots, _, err = unstructured.NestedMap(obj.Object, "metadata", "annotations")
if err != nil {
return nil, nil, fmt.Errorf("unstructured.NestedMap error: %s", err)
}
}
if annots == nil {
annots = make(map[string]interface{})
}
val, ok := annots[k]
if !ok {
continue
}
strVal := toString(val)
replacement, ok := valToReplacement[strVal]
if !ok {
replacement = nextReplacement
nextReplacement = nextReplacement + "++++"
valToReplacement[strVal] = replacement
}
annots[k] = replacement
err = unstructured.SetNestedMap(obj.Object, annots, "metadata", "annotations")
err := unstructured.SetNestedField(obj.Object, data, fields...)
if err != nil {
return nil, nil, fmt.Errorf("unstructured.SetNestedField error: %s", err)
return nil, nil, nil, fmt.Errorf("unstructured.SetNestedField error: %s", err)
}
}
}

// hide last-applied-config annotation
if live != nil && orig != nil {
annotations := live.GetAnnotations()
if annotations == nil {
annotations = make(map[string]string)
}
lastAppliedData, err := json.Marshal(orig)
if err != nil {
return nil, nil, fmt.Errorf("error marshaling json: %s", err)
}
annotations[corev1.LastAppliedConfigAnnotation] = string(lastAppliedData)
live.SetAnnotations(annotations)
}
return target, live, nil
return target, live, orig, nil
}

func toString(val interface{}) string {
Expand All @@ -1097,6 +1075,14 @@ func toString(val interface{}) string {
return fmt.Sprintf("%s", val)
}

func convertSliceToMap(s []string) map[string]bool {
m := make(map[string]bool)
for _, k := range s {
m[k] = true
}
return m
}

// remarshal checks resource kind and version and re-marshal using corresponding struct custom marshaller.
// This ensures that expected resource state is formatter same as actual resource state in kubernetes
// and allows to find differences between actual and target states more accurately.
Expand Down
32 changes: 19 additions & 13 deletions pkg/diff/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -986,7 +986,9 @@ var (
func TestHideSecretDataSameKeysDifferentValues(t *testing.T) {
target, live, err := HideSecretData(
createSecret(map[string]string{"key1": "test", "key2": "test"}),
createSecret(map[string]string{"key1": "test-1", "key2": "test-1"}))
createSecret(map[string]string{"key1": "test-1", "key2": "test-1"}),
nil,
)
require.NoError(t, err)

assert.Equal(t, map[string]interface{}{"key1": replacement1, "key2": replacement1}, secretData(target))
Expand All @@ -996,7 +998,9 @@ func TestHideSecretDataSameKeysDifferentValues(t *testing.T) {
func TestHideSecretDataSameKeysSameValues(t *testing.T) {
target, live, err := HideSecretData(
createSecret(map[string]string{"key1": "test", "key2": "test"}),
createSecret(map[string]string{"key1": "test", "key2": "test"}))
createSecret(map[string]string{"key1": "test", "key2": "test"}),
nil,
)
require.NoError(t, err)

assert.Equal(t, map[string]interface{}{"key1": replacement1, "key2": replacement1}, secretData(target))
Expand All @@ -1006,7 +1010,9 @@ func TestHideSecretDataSameKeysSameValues(t *testing.T) {
func TestHideSecretDataDifferentKeysDifferentValues(t *testing.T) {
target, live, err := HideSecretData(
createSecret(map[string]string{"key1": "test", "key2": "test"}),
createSecret(map[string]string{"key2": "test-1", "key3": "test-1"}))
createSecret(map[string]string{"key2": "test-1", "key3": "test-1"}),
nil,
)
require.NoError(t, err)

assert.Equal(t, map[string]interface{}{"key1": replacement1, "key2": replacement1}, secretData(target))
Expand All @@ -1016,26 +1022,26 @@ func TestHideSecretDataDifferentKeysDifferentValues(t *testing.T) {
func TestHideSecretAnnotations(t *testing.T) {
tests := []struct {
name string
hideAnnots []string
hideAnnots map[string]bool
annots map[string]interface{}
expectedAnnots map[string]interface{}
targetNil bool
}{
{
name: "no hidden annotations",
hideAnnots: []string{""},
hideAnnots: nil,
annots: map[string]interface{}{"token/value": "secret", "key": "secret-key", "app": "test"},
expectedAnnots: map[string]interface{}{"token/value": "secret", "key": "secret-key", "app": "test"},
},
{
name: "hide annotations",
hideAnnots: []string{"token/value", "key"},
hideAnnots: map[string]bool{"token/value": true, "key": true},
annots: map[string]interface{}{"token/value": "secret", "key": "secret-key", "app": "test"},
expectedAnnots: map[string]interface{}{"token/value": replacement1, "key": replacement1, "app": "test"},
},
{
name: "hide annotations in last-applied-config",
hideAnnots: []string{"token/value", "key"},
hideAnnots: map[string]bool{"token/value": true, "key": true},
annots: map[string]interface{}{
"token/value": "secret",
"app": "test",
Expand All @@ -1050,7 +1056,7 @@ func TestHideSecretAnnotations(t *testing.T) {
},
{
name: "hide annotations for malformed annotations",
hideAnnots: []string{"token/value", "key"},
hideAnnots: map[string]bool{"token/value": true, "key": true},
annots: map[string]interface{}{"token/value": 0, "key": "secret", "app": true},
expectedAnnots: map[string]interface{}{"token/value": replacement1, "key": replacement1, "app": true},
},
Expand Down Expand Up @@ -1078,7 +1084,7 @@ func TestHideSecretAnnotations(t *testing.T) {
targetUn = nil
}

target, live, err := HideSecretData(targetUn, liveUn, tt.hideAnnots...)
target, live, err := HideSecretData(targetUn, liveUn, tt.hideAnnots)
require.NoError(t, err)

// verify configured annotations are hidden
Expand All @@ -1097,7 +1103,7 @@ func TestHideSecretAnnotations(t *testing.T) {
}

func TestHideSecretAnnotationsPreserveDifference(t *testing.T) {
hideAnnots := []string{"token/value"}
hideAnnots := map[string]bool{"token/value": true}

liveUn := &unstructured.Unstructured{
Object: map[string]interface{}{
Expand Down Expand Up @@ -1125,7 +1131,7 @@ func TestHideSecretAnnotationsPreserveDifference(t *testing.T) {
liveUn = remarshal(liveUn, applyOptions(diffOptionsForTest()))
targetUn = remarshal(targetUn, applyOptions(diffOptionsForTest()))

target, live, err := HideSecretData(targetUn, liveUn, hideAnnots...)
target, live, err := HideSecretData(targetUn, liveUn, hideAnnots)
require.NoError(t, err)

liveAnnots := live.GetAnnotations()
Expand Down Expand Up @@ -1204,7 +1210,7 @@ func TestHideSecretDataHandleEmptySecret(t *testing.T) {
liveSecret := bytesToUnstructured(t, getLiveSecretJsonBytes())

// when
target, live, err := HideSecretData(targetSecret, liveSecret)
target, live, err := HideSecretData(targetSecret, liveSecret, nil)

// then
assert.NoError(t, err)
Expand All @@ -1222,7 +1228,7 @@ func TestHideSecretDataLastAppliedConfig(t *testing.T) {
require.NoError(t, err)
liveSecret.SetAnnotations(map[string]string{corev1.LastAppliedConfigAnnotation: string(lastAppliedStr)})

target, live, err := HideSecretData(targetSecret, liveSecret)
target, live, err := HideSecretData(targetSecret, liveSecret, nil)
require.NoError(t, err)
err = json.Unmarshal([]byte(live.GetAnnotations()[corev1.LastAppliedConfigAnnotation]), &lastAppliedSecret)
require.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/utils/kube/resource_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (k *kubectlResourceOperations) runResourceCommand(ctx context.Context, obj
if err != nil {
return "", err
}
redacted, _, err := diff.HideSecretData(&obj, nil)
redacted, _, err := diff.HideSecretData(&obj, nil, nil)
if err != nil {
return "", err
}
Expand Down

0 comments on commit 6395c89

Please sign in to comment.