in pkg/bundle/compare/diff.go [55:206]
func Diff(src, dst *bundlev1.Bundle) ([]DiffItem, error) {
// Check arguments
if src == nil {
return nil, fmt.Errorf("unable to diff with a nil source")
}
if dst == nil {
return nil, fmt.Errorf("unable to diff with a nil destination")
}
diffs := []DiffItem{}
// Index source packages
srcIndex := map[string]*bundlev1.Package{}
for _, srcPkg := range src.Packages {
if srcPkg == nil || srcPkg.Secrets == nil {
continue
}
srcIndex[srcPkg.Name] = srcPkg
}
// Index destination packages
dstIndex := map[string]*bundlev1.Package{}
for _, dstPkg := range dst.Packages {
if dstPkg == nil || dstPkg.Secrets == nil {
continue
}
dstIndex[dstPkg.Name] = dstPkg
if _, ok := srcIndex[dstPkg.Name]; !ok {
// Package has been added
diffs = append(diffs, DiffItem{
Operation: Add,
Type: "package",
Path: dstPkg.Name,
})
// Add keys
for _, s := range dstPkg.Secrets.Data {
if s == nil {
continue
}
// Unpack secret value
var data string
if err := secret.Unpack(s.Value, &data); err != nil {
return nil, fmt.Errorf("unable to unpack '%s' - '%s' secret value: %w", dstPkg.Name, s.Key, err)
}
diffs = append(diffs, DiffItem{
Operation: Add,
Type: "secret",
Path: fmt.Sprintf("%s#%s", dstPkg.Name, s.Key),
Value: data,
})
}
}
}
// Compute package changes
for n, sp := range srcIndex {
dp, ok := dstIndex[n]
if !ok {
// Not exist in destination bundle
diffs = append(diffs, DiffItem{
Operation: Remove,
Type: "package",
Path: sp.Name,
})
continue
}
// Index secret data
srcSecretIndex := map[string]*bundlev1.KV{}
for _, ss := range sp.Secrets.Data {
if ss == nil {
continue
}
srcSecretIndex[ss.Key] = ss
}
dstSecretIndex := map[string]*bundlev1.KV{}
for _, ds := range dp.Secrets.Data {
if ds == nil {
continue
}
dstSecretIndex[ds.Key] = ds
oldValue, ok := srcSecretIndex[ds.Key]
if !ok {
// Secret has been added
var data string
if err := secret.Unpack(ds.Value, &data); err != nil {
return nil, fmt.Errorf("unable to unpack '%s' - '%s' secret value: %w", dp.Name, ds.Key, err)
}
diffs = append(diffs, DiffItem{
Operation: Add,
Type: "secret",
Path: fmt.Sprintf("%s#%s", dp.Name, ds.Key),
Value: data,
})
continue
}
// Skip if key does not match
if !strings.EqualFold(oldValue.Key, ds.Key) {
continue
}
// Compare values
if !security.SecureCompare(oldValue.Value, ds.Value) {
// Secret has been replaced
var data string
if err := secret.Unpack(ds.Value, &data); err != nil {
return nil, fmt.Errorf("unable to unpack '%s' - '%s' secret value: %w", dp.Name, ds.Key, err)
}
diffs = append(diffs, DiffItem{
Operation: Replace,
Type: "secret",
Path: fmt.Sprintf("%s#%s", dp.Name, ds.Key),
Value: data,
})
}
}
// Clean removed source secrets
for k := range srcSecretIndex {
if _, ok := dstSecretIndex[k]; !ok {
diffs = append(diffs, DiffItem{
Operation: Remove,
Type: "secret",
Path: fmt.Sprintf("%s#%s", dp.Name, k),
})
}
}
}
// Sort diff
sort.SliceStable(diffs, func(i, j int) bool {
var (
x = diffs[i]
y = diffs[j]
)
// Sort by patch descending
return x.Path < y.Path
})
// No error
return diffs, nil
}