Files

44 lines
1.5 KiB
Go

package libpolicy
import (
"hash/fnv"
"sort"
"strconv"
"github.com/segmentio/encoding/json"
portainer "github.com/portainer/portainer/api"
)
// ConfigFingerprint is the generic primitive: FNV-1a over serialized policy
// config bytes. It is a change detector, not a security boundary; collisions
// are acceptable because a later poll or policy edit will retry reconciliation.
// Callers must ensure the bytes are deterministic (e.g. collections sorted
// before marshaling).
//
// New policy types should call this after marshaling their own config struct.
func ConfigFingerprint(config []byte) string {
h := fnv.New32a()
h.Write(config)
return strconv.FormatUint(uint64(h.Sum32()), 16)
}
// HelmPolicyFingerprint computes a fingerprint for a Helm policy from its chart
// summaries. Charts are sorted by name before hashing so the result is
// order-independent. The restore manifest is excluded because it does not
// affect what gets installed.
//
// Both server-ee and the agent import this function to guarantee they compute
// identical fingerprints for the same chart summaries.
func HelmPolicyFingerprint(chartSummaries []portainer.PolicyChartSummary) string {
sorted := make([]portainer.PolicyChartSummary, len(chartSummaries))
copy(sorted, chartSummaries)
sort.Slice(sorted, func(i, j int) bool { return sorted[i].ChartName < sorted[j].ChartName })
b, err := json.Marshal(portainer.HelmPolicyConfig{Charts: sorted})
if err != nil {
// json.Marshal of a known struct with no custom marshalers cannot error.
return ""
}
return ConfigFingerprint(b)
}