Skip to content

Commit b1ae813

Browse files
committed
Introduce new yaml package with Encode func
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
1 parent 0f6a8d1 commit b1ae813

13 files changed

+4638
-222
lines changed

api/go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
k8s.io/apiextensions-apiserver v0.27.3
99
k8s.io/apimachinery v0.27.3
1010
sigs.k8s.io/controller-runtime v0.15.0
11+
sigs.k8s.io/yaml v1.3.0
1112
)
1213

1314
require (

api/go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,4 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h6
103103
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
104104
sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
105105
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
106+
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=

api/v2beta2/helmrelease_types.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ limitations under the License.
1717
package v2beta2
1818

1919
import (
20-
"encoding/json"
2120
"fmt"
2221
"strings"
2322
"time"
2423

2524
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2625
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2726
"k8s.io/apimachinery/pkg/types"
27+
"sigs.k8s.io/yaml"
2828

2929
"github.com/fluxcd/pkg/apis/kustomize"
3030
"github.com/fluxcd/pkg/apis/meta"
@@ -1118,7 +1118,7 @@ func (in HelmRelease) GetRequeueAfter() time.Duration {
11181118
func (in HelmRelease) GetValues() map[string]interface{} {
11191119
var values map[string]interface{}
11201120
if in.Spec.Values != nil {
1121-
_ = json.Unmarshal(in.Spec.Values.Raw, &values)
1121+
_ = yaml.Unmarshal(in.Spec.Values.Raw, &values)
11221122
}
11231123
return values
11241124
}

internal/chartutil/digest.go

+21-4
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,18 @@ package chartutil
1919
import (
2020
"github.com/opencontainers/go-digest"
2121
"helm.sh/helm/v3/pkg/chartutil"
22+
23+
intyaml "github.com/fluxcd/helm-controller/internal/yaml"
2224
)
2325

2426
// DigestValues calculates the digest of the values using the provided algorithm.
2527
// The caller is responsible for ensuring that the algorithm is supported.
2628
func DigestValues(algo digest.Algorithm, values chartutil.Values) digest.Digest {
2729
digester := algo.Digester()
28-
if err := values.Encode(digester.Hash()); err != nil {
29-
return ""
30+
if values = valuesOrNil(values); values != nil {
31+
if err := intyaml.Encode(digester.Hash(), values, intyaml.SortMapSlice); err != nil {
32+
return ""
33+
}
3034
}
3135
return digester.Digest()
3236
}
@@ -36,9 +40,22 @@ func VerifyValues(digest digest.Digest, values chartutil.Values) bool {
3640
if digest.Validate() != nil {
3741
return false
3842
}
43+
3944
verifier := digest.Verifier()
40-
if err := values.Encode(verifier); err != nil {
41-
return false
45+
if values = valuesOrNil(values); values != nil {
46+
if err := intyaml.Encode(verifier, values, intyaml.SortMapSlice); err != nil {
47+
return false
48+
}
4249
}
4350
return verifier.Verified()
4451
}
52+
53+
// valuesOrNil returns nil if the values are empty, otherwise the values are
54+
// returned. This is used to ensure that the digest is calculated against nil
55+
// opposed to an empty object.
56+
func valuesOrNil(values chartutil.Values) chartutil.Values {
57+
if values != nil && len(values) == 0 {
58+
return nil
59+
}
60+
return values
61+
}

internal/chartutil/digest_test.go

+188-11
Original file line numberDiff line numberDiff line change
@@ -23,45 +23,222 @@ import (
2323
"helm.sh/helm/v3/pkg/chartutil"
2424
)
2525

26-
const testDigestAlgo = digest.SHA256
27-
2826
func TestDigestValues(t *testing.T) {
2927
tests := []struct {
3028
name string
29+
algo digest.Algorithm
3130
values chartutil.Values
3231
want digest.Digest
3332
}{
3433
{
3534
name: "empty",
35+
algo: digest.SHA256,
3636
values: chartutil.Values{},
37-
want: "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356",
37+
want: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
38+
},
39+
{
40+
name: "nil",
41+
algo: digest.SHA256,
42+
values: nil,
43+
want: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
3844
},
3945
{
4046
name: "value map",
47+
algo: digest.SHA256,
4148
values: chartutil.Values{
42-
"foo": "bar",
43-
"baz": map[string]string{
44-
"cool": "stuff",
49+
"replicas": 3,
50+
"image": map[string]interface{}{
51+
"tag": "latest",
52+
"repository": "nginx",
53+
},
54+
"ports": []interface{}{
55+
map[string]interface{}{
56+
"protocol": "TCP",
57+
"port": 8080,
58+
},
59+
map[string]interface{}{
60+
"port": 9090,
61+
"protocol": "UDP",
62+
},
4563
},
4664
},
47-
want: "sha256:3f3641788a2d4abda3534eaa90c90b54916e4c6e3a5b2e1b24758b7bfa701ecd",
65+
want: "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6",
4866
},
4967
{
5068
name: "value map in different order",
69+
algo: digest.SHA256,
5170
values: chartutil.Values{
52-
"baz": map[string]string{
53-
"cool": "stuff",
71+
"image": map[string]interface{}{
72+
"repository": "nginx",
73+
"tag": "latest",
74+
},
75+
"ports": []interface{}{
76+
map[string]interface{}{
77+
"port": 8080,
78+
"protocol": "TCP",
79+
},
80+
map[string]interface{}{
81+
"port": 9090,
82+
"protocol": "UDP",
83+
},
84+
},
85+
"replicas": 3,
86+
},
87+
want: "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6",
88+
},
89+
{
90+
// Explicit test for something that does not work with sigs.k8s.io/yaml.
91+
// See: https://go.dev/play/p/KRyfK9ZobZx
92+
name: "values map with numeric keys",
93+
algo: digest.SHA256,
94+
values: chartutil.Values{
95+
"replicas": 3,
96+
"test": map[string]interface{}{
97+
"632bd80235a05f4192aefade": "value1",
98+
"632bd80ddf416cf32fd50679": "value2",
99+
"632bd817c559818a52307da2": "value3",
100+
"632bd82398e71231a98004b6": "value4",
101+
},
102+
},
103+
want: "sha256:8a980fcbeadd6f05818f07e8aec14070c22250ca3d96af1fcd5f93b3e85b4d70",
104+
},
105+
{
106+
name: "values map with numeric keys in different order",
107+
algo: digest.SHA256,
108+
values: chartutil.Values{
109+
"test": map[string]interface{}{
110+
"632bd82398e71231a98004b6": "value4",
111+
"632bd817c559818a52307da2": "value3",
112+
"632bd80ddf416cf32fd50679": "value2",
113+
"632bd80235a05f4192aefade": "value1",
54114
},
115+
"replicas": 3,
116+
},
117+
want: "sha256:8a980fcbeadd6f05818f07e8aec14070c22250ca3d96af1fcd5f93b3e85b4d70",
118+
},
119+
{
120+
name: "using different algorithm",
121+
algo: digest.SHA512,
122+
values: chartutil.Values{
55123
"foo": "bar",
124+
"baz": map[string]interface{}{
125+
"cool": "stuff",
126+
},
56127
},
57-
want: "sha256:3f3641788a2d4abda3534eaa90c90b54916e4c6e3a5b2e1b24758b7bfa701ecd",
128+
want: "sha512:b5f9cd4855ca3b08afd602557f373069b1732ce2e6d52341481b0d38f1938452e9d7759ab177c66699962b592f20ceded03eea3cd405d8670578c47842e2c550",
58129
},
59130
}
60131
for _, tt := range tests {
61132
t.Run(tt.name, func(t *testing.T) {
62-
if got := DigestValues(testDigestAlgo, tt.values); got != tt.want {
133+
if got := DigestValues(tt.algo, tt.values); got != tt.want {
63134
t.Errorf("DigestValues() = %v, want %v", got, tt.want)
64135
}
65136
})
66137
}
67138
}
139+
140+
func TestVerifyValues(t *testing.T) {
141+
tests := []struct {
142+
name string
143+
digest digest.Digest
144+
values chartutil.Values
145+
want bool
146+
}{
147+
{
148+
name: "empty values",
149+
digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
150+
values: chartutil.Values{},
151+
want: true,
152+
},
153+
{
154+
name: "nil values",
155+
digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
156+
values: nil,
157+
want: true,
158+
},
159+
{
160+
name: "empty digest",
161+
digest: "",
162+
want: false,
163+
},
164+
{
165+
name: "invalid digest",
166+
digest: "sha512:invalid",
167+
values: nil,
168+
want: false,
169+
},
170+
{
171+
name: "matching values",
172+
digest: "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6",
173+
values: chartutil.Values{
174+
"image": map[string]interface{}{
175+
"repository": "nginx",
176+
"tag": "latest",
177+
},
178+
"ports": []interface{}{
179+
map[string]interface{}{
180+
"port": 8080,
181+
"protocol": "TCP",
182+
},
183+
map[string]interface{}{
184+
"port": 9090,
185+
"protocol": "UDP",
186+
},
187+
},
188+
"replicas": 3,
189+
},
190+
want: true,
191+
},
192+
{
193+
name: "matching values in different order",
194+
digest: "sha256:fcdc2b0de1581a3633ada4afee3f918f6eaa5b5ab38c3fef03d5b48d3f85d9f6",
195+
values: chartutil.Values{
196+
"replicas": 3,
197+
"image": map[string]interface{}{
198+
"tag": "latest",
199+
"repository": "nginx",
200+
},
201+
"ports": []interface{}{
202+
map[string]interface{}{
203+
"protocol": "TCP",
204+
"port": 8080,
205+
},
206+
map[string]interface{}{
207+
"port": 9090,
208+
"protocol": "UDP",
209+
},
210+
},
211+
},
212+
want: true,
213+
},
214+
{
215+
name: "matching values with numeric keys",
216+
digest: "sha256:8a980fcbeadd6f05818f07e8aec14070c22250ca3d96af1fcd5f93b3e85b4d70",
217+
values: chartutil.Values{
218+
"replicas": 3,
219+
"test": map[string]interface{}{
220+
"632bd80235a05f4192aefade": "value1",
221+
"632bd80ddf416cf32fd50679": "value2",
222+
"632bd817c559818a52307da2": "value3",
223+
"632bd82398e71231a98004b6": "value4",
224+
},
225+
},
226+
want: true,
227+
},
228+
{
229+
name: "mismatching values",
230+
digest: "sha256:3f3641788a2d4abda3534eaa90c90b54916e4c6e3a5b2e1b24758b7bfa701ecd",
231+
values: chartutil.Values{
232+
"foo": "bar",
233+
},
234+
want: false,
235+
},
236+
}
237+
for _, tt := range tests {
238+
t.Run(tt.name, func(t *testing.T) {
239+
if got := VerifyValues(tt.digest, tt.values); got != tt.want {
240+
t.Errorf("VerifyValues() = %v, want %v", got, tt.want)
241+
}
242+
})
243+
}
244+
}

internal/chartutil/values_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
"k8s.io/apimachinery/pkg/runtime"
2929
"sigs.k8s.io/controller-runtime/pkg/client/fake"
3030

31-
v2 "github.com/fluxcd/helm-controller/api/v2beta1"
31+
v2 "github.com/fluxcd/helm-controller/api/v2beta2"
3232
)
3333

3434
func TestChartValuesFromReferences(t *testing.T) {

0 commit comments

Comments
 (0)