11package diff
22
33import (
4+ "bytes"
45 "fmt"
56 "io"
67 "math"
@@ -9,19 +10,27 @@ import (
910
1011 "github.com/aryann/difflib"
1112 "github.com/mgutz/ansi"
13+ v1 "k8s.io/api/core/v1"
14+ "k8s.io/apimachinery/pkg/runtime/serializer/json"
15+ "k8s.io/apimachinery/pkg/util/yaml"
16+ "k8s.io/client-go/kubernetes/scheme"
1217
1318 "github.com/databus23/helm-diff/manifest"
1419)
1520
1621// Manifests diff on manifests
17- func Manifests (oldIndex , newIndex map [string ]* manifest.MappingResult , suppressedKinds []string , context int , to io.Writer ) bool {
22+ func Manifests (oldIndex , newIndex map [string ]* manifest.MappingResult , suppressedKinds []string , showSecrets bool , context int , to io.Writer ) bool {
1823 seenAnyChanges := false
1924 emptyMapping := & manifest.MappingResult {}
2025 for key , oldContent := range oldIndex {
2126 if newContent , ok := newIndex [key ]; ok {
2227 if oldContent .Content != newContent .Content {
2328 // modified
2429 fmt .Fprintf (to , ansi .Color ("%s has changed:" , "yellow" )+ "\n " , key )
30+ if ! showSecrets {
31+ redactSecrets (oldContent , newContent )
32+ }
33+
2534 diffs := diffMappingResults (oldContent , newContent )
2635 if len (diffs ) > 0 {
2736 seenAnyChanges = true
@@ -31,6 +40,10 @@ func Manifests(oldIndex, newIndex map[string]*manifest.MappingResult, suppressed
3140 } else {
3241 // removed
3342 fmt .Fprintf (to , ansi .Color ("%s has been removed:" , "yellow" )+ "\n " , key )
43+ if ! showSecrets {
44+ redactSecrets (oldContent , nil )
45+
46+ }
3447 diffs := diffMappingResults (oldContent , emptyMapping )
3548 if len (diffs ) > 0 {
3649 seenAnyChanges = true
@@ -43,6 +56,9 @@ func Manifests(oldIndex, newIndex map[string]*manifest.MappingResult, suppressed
4356 if _ , ok := oldIndex [key ]; ! ok {
4457 // added
4558 fmt .Fprintf (to , ansi .Color ("%s has been added:" , "yellow" )+ "\n " , key )
59+ if ! showSecrets {
60+ redactSecrets (nil , newContent )
61+ }
4662 diffs := diffMappingResults (emptyMapping , newContent )
4763 if len (diffs ) > 0 {
4864 seenAnyChanges = true
@@ -53,11 +69,79 @@ func Manifests(oldIndex, newIndex map[string]*manifest.MappingResult, suppressed
5369 return seenAnyChanges
5470}
5571
72+ func redactSecrets (old , new * manifest.MappingResult ) {
73+ if old != nil && old .Kind != "Secret" && new != nil && new .Kind != "Secret" {
74+ return
75+ }
76+ serializer := json .NewYAMLSerializer (json .DefaultMetaFactory , scheme .Scheme ,
77+ scheme .Scheme )
78+ var oldSecret , newSecret v1.Secret
79+
80+ if old != nil {
81+ if err := yaml .NewYAMLToJSONDecoder (bytes .NewBufferString (old .Content )).Decode (& oldSecret ); err != nil {
82+ old .Content = fmt .Sprintf ("Error parsing old secret: %s" , err )
83+ }
84+ }
85+ if new != nil {
86+ if err := yaml .NewYAMLToJSONDecoder (bytes .NewBufferString (new .Content )).Decode (& newSecret ); err != nil {
87+ new .Content = fmt .Sprintf ("Error parsing new secret: %s" , err )
88+ }
89+ }
90+ if old != nil {
91+ oldSecret .StringData = make (map [string ]string , len (oldSecret .Data ))
92+ for k , v := range oldSecret .Data {
93+ if new != nil && bytes .Equal (v , newSecret .Data [k ]) {
94+ oldSecret .StringData [k ] = fmt .Sprintf ("REDACTED # (%d bytes)" , len (v ))
95+ } else {
96+ oldSecret .StringData [k ] = fmt .Sprintf ("-------- # (%d bytes)" , len (v ))
97+ }
98+ }
99+ }
100+ if new != nil {
101+ newSecret .StringData = make (map [string ]string , len (newSecret .Data ))
102+ for k , v := range newSecret .Data {
103+ if old != nil && bytes .Equal (v , oldSecret .Data [k ]) {
104+ newSecret .StringData [k ] = fmt .Sprintf ("REDACTED # (%d bytes)" , len (v ))
105+ } else {
106+ newSecret .StringData [k ] = fmt .Sprintf ("++++++++ # (%d bytes)" , len (v ))
107+ }
108+ }
109+ }
110+ // remove Data field now that we are using StringData for serialization
111+ var buf bytes.Buffer
112+ if old != nil {
113+ oldSecret .Data = nil
114+ if err := serializer .Encode (& oldSecret , & buf ); err != nil {
115+
116+ }
117+ old .Content = getComment (old .Content ) + strings .Replace (strings .Replace (buf .String (), "stringData" , "data" , 1 ), " creationTimestamp: null\n " , "" , 1 )
118+ buf .Reset () //reuse buffer for new secret
119+ }
120+ if new != nil {
121+ newSecret .Data = nil
122+ if err := serializer .Encode (& newSecret , & buf ); err != nil {
123+
124+ }
125+ new .Content = getComment (new .Content ) + strings .Replace (strings .Replace (buf .String (), "stringData" , "data" , 1 ), " creationTimestamp: null\n " , "" , 1 )
126+ }
127+ }
128+
129+ // return the first line of a string if its a comment.
130+ // This gives as the # Source: lines from the rendering
131+ func getComment (s string ) string {
132+ i := strings .Index (s , "\n " )
133+ if i < 0 || ! strings .HasPrefix (s , "#" ) {
134+ return ""
135+ }
136+ return s [:i + 1 ]
137+
138+ }
139+
56140// Releases reindex the content based on the template names and pass it to Manifests
57- func Releases (oldIndex , newIndex map [string ]* manifest.MappingResult , suppressedKinds []string , context int , to io.Writer ) bool {
141+ func Releases (oldIndex , newIndex map [string ]* manifest.MappingResult , suppressedKinds []string , showSecrets bool , context int , to io.Writer ) bool {
58142 oldIndex = reIndexForRelease (oldIndex )
59143 newIndex = reIndexForRelease (newIndex )
60- return Manifests (oldIndex , newIndex , suppressedKinds , context , to )
144+ return Manifests (oldIndex , newIndex , suppressedKinds , showSecrets , context , to )
61145}
62146
63147func diffMappingResults (oldContent * manifest.MappingResult , newContent * manifest.MappingResult ) []difflib.DiffRecord {
@@ -71,6 +155,7 @@ func diffStrings(before, after string) []difflib.DiffRecord {
71155
72156func printDiffRecords (suppressedKinds []string , kind string , context int , diffs []difflib.DiffRecord , to io.Writer ) {
73157 for _ , ckind := range suppressedKinds {
158+
74159 if ckind == kind {
75160 str := fmt .Sprintf ("+ Changes suppressed on sensitive content of type %s\n " , kind )
76161 fmt .Fprintf (to , ansi .Color (str , "yellow" ))
0 commit comments