Skip to content

Commit 85a7667

Browse files
committed
Add unit tests for all bundle signing functions
1 parent 8bea646 commit 85a7667

File tree

2 files changed

+311
-0
lines changed

2 files changed

+311
-0
lines changed

release/cli/pkg/signature/manifest.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
115
package signature
216

317
import (
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package signature
16+
17+
import (
18+
"context"
19+
"testing"
20+
21+
. "github.com/onsi/gomega"
22+
23+
anywherev1alpha1 "github.com/aws/eks-anywhere/release/api/v1alpha1"
24+
)
25+
26+
func TestGetBundleSignature(t *testing.T) {
27+
testCases := []struct {
28+
testName string
29+
bundle *anywherev1alpha1.Bundles
30+
key string
31+
expectErrSubstr string
32+
}{
33+
{
34+
testName: "Nil bundle",
35+
bundle: nil,
36+
key: KmsKey,
37+
expectErrSubstr: "computing digest:",
38+
},
39+
{
40+
testName: "Excluding fields from bundle with minimal valid data",
41+
bundle: &anywherev1alpha1.Bundles{
42+
Spec: anywherev1alpha1.BundlesSpec{
43+
VersionsBundles: []anywherev1alpha1.VersionsBundle{
44+
{
45+
KubeVersion: "1.31",
46+
},
47+
},
48+
},
49+
},
50+
key: KmsKey,
51+
expectErrSubstr: "",
52+
},
53+
{
54+
testName: "Excluding fields from a fully populated Bundles object",
55+
bundle: &anywherev1alpha1.Bundles{
56+
Spec: anywherev1alpha1.BundlesSpec{
57+
Number: 10,
58+
CliMinVersion: "v1.0.0",
59+
CliMaxVersion: "v2.0.0",
60+
VersionsBundles: []anywherev1alpha1.VersionsBundle{
61+
{
62+
KubeVersion: "1.28",
63+
EndOfStandardSupport: "2024-10-10",
64+
EksD: anywherev1alpha1.EksDRelease{
65+
Name: "eks-d-1-25",
66+
ReleaseChannel: "1-25",
67+
KubeVersion: "1.25",
68+
EksDReleaseUrl: "https://example.com/release.yaml",
69+
},
70+
CertManager: anywherev1alpha1.CertManagerBundle{
71+
Version: "v1.11.0",
72+
Acmesolver: anywherev1alpha1.Image{
73+
URI: "public.ecr.aws/acmesolver:latest",
74+
},
75+
Cainjector: anywherev1alpha1.Image{
76+
URI: "public.ecr.aws/cainjector:latest",
77+
},
78+
Controller: anywherev1alpha1.Image{
79+
URI: "public.ecr.aws/cert-manager-controller:latest",
80+
},
81+
Startupapicheck: anywherev1alpha1.Image{
82+
URI: "public.ecr.aws/startupapicheck:latest",
83+
},
84+
Webhook: anywherev1alpha1.Image{
85+
URI: "public.ecr.aws/webhook:latest",
86+
},
87+
Manifest: anywherev1alpha1.Manifest{
88+
URI: "https://example.com/cert-manager.yaml",
89+
},
90+
},
91+
Eksa: anywherev1alpha1.EksaBundle{
92+
Version: "v0.0.1-dev",
93+
CliTools: anywherev1alpha1.Image{
94+
URI: "public.ecr.aws/eks-anywhere-cli-tools:latest",
95+
},
96+
},
97+
},
98+
{
99+
KubeVersion: "1.26",
100+
},
101+
},
102+
},
103+
},
104+
key: KmsKey,
105+
expectErrSubstr: "",
106+
},
107+
}
108+
109+
for _, tt := range testCases {
110+
t.Run(tt.testName, func(t *testing.T) {
111+
g := NewWithT(t)
112+
113+
ctx := context.Background()
114+
sig, err := GetBundleSignature(ctx, tt.bundle, tt.key)
115+
116+
if tt.expectErrSubstr == "" {
117+
// Expecting no particular error substring -> test for success
118+
g.Expect(err).NotTo(HaveOccurred(),
119+
"Expected no error but got error: %v", err)
120+
g.Expect(sig).NotTo(BeEmpty(),
121+
"Expected signature string to be non-empty on success")
122+
} else {
123+
// Expecting an error substring -> test for error presence
124+
g.Expect(err).To(HaveOccurred(),
125+
"Expected an error but got none")
126+
g.Expect(err.Error()).To(ContainSubstring(tt.expectErrSubstr),
127+
"Error message should contain substring %q, got: %v", tt.expectErrSubstr, err)
128+
g.Expect(sig).To(BeEmpty(),
129+
"Expected signature to be empty when error occurs")
130+
}
131+
})
132+
}
133+
}
134+
135+
func TestGetDigest(t *testing.T) {
136+
testCases := []struct {
137+
testName string
138+
bundle *anywherev1alpha1.Bundles
139+
expectErrSubstr string
140+
}{
141+
{
142+
testName: "Simple valid bundle",
143+
bundle: &anywherev1alpha1.Bundles{
144+
Spec: anywherev1alpha1.BundlesSpec{
145+
Number: 1,
146+
VersionsBundles: []anywherev1alpha1.VersionsBundle{
147+
{
148+
KubeVersion: "1.31",
149+
},
150+
},
151+
},
152+
},
153+
expectErrSubstr: "",
154+
},
155+
{
156+
testName: "Another valid bundle with more fields",
157+
bundle: &anywherev1alpha1.Bundles{
158+
Spec: anywherev1alpha1.BundlesSpec{
159+
Number: 10,
160+
CliMinVersion: "v0.0.1",
161+
VersionsBundles: []anywherev1alpha1.VersionsBundle{
162+
{
163+
KubeVersion: "1.28",
164+
},
165+
{
166+
KubeVersion: "1.29",
167+
},
168+
},
169+
},
170+
},
171+
expectErrSubstr: "",
172+
},
173+
}
174+
175+
for _, tt := range testCases {
176+
t.Run(tt.testName, func(t *testing.T) {
177+
g := NewWithT(t)
178+
179+
digest, filtered, err := getDigest(tt.bundle)
180+
if tt.expectErrSubstr == "" {
181+
g.Expect(err).NotTo(HaveOccurred(), "Expected success but got error")
182+
g.Expect(digest).NotTo(BeZero(),
183+
"Expected digest to be non-zero array")
184+
g.Expect(filtered).NotTo(BeEmpty(),
185+
"Expected filtered bytes to be non-empty")
186+
} else {
187+
g.Expect(err).To(HaveOccurred(),
188+
"Expected error but got none")
189+
g.Expect(err.Error()).To(ContainSubstring(tt.expectErrSubstr),
190+
"Error message should contain substring %q, got: %v",
191+
tt.expectErrSubstr, err)
192+
g.Expect(digest).To(BeZero())
193+
g.Expect(filtered).To(BeNil())
194+
}
195+
})
196+
}
197+
}
198+
199+
func TestFilterExcludes(t *testing.T) {
200+
testCases := []struct {
201+
testName string
202+
jsonPayload string
203+
expectErrSubstr string
204+
expectExclude []string // substrings we expect to NOT be present
205+
expectInclude []string // substrings we expect to be present
206+
}{
207+
{
208+
testName: "Valid JSON with known excludes",
209+
jsonPayload: `{
210+
"metadata": {
211+
"creationTimestamp": "2021-09-01T00:00:00Z",
212+
"annotations": { "key": "value" }
213+
},
214+
"status": {
215+
"someStatus": "info"
216+
},
217+
"spec": {
218+
"versionsBundles": [{
219+
"kubeVersion": "1.28",
220+
"endOfExtendedSupport": "2024-12-31",
221+
"eksD": {
222+
"channel": "1-28",
223+
"components": "https://distro.eks.amazonaws.com/crds/releases.distro.eks.amazonaws.com-v1alpha1.yaml",
224+
"gitCommit": "3c3ff5d3aaa7417b906549756da44f60af5df03d",
225+
"kubeVersion": "v1.28.15",
226+
"manifestUrl": "https://distro.eks.amazonaws.com/kubernetes-1-28/kubernetes-1-28-eks-37.yaml",
227+
"name": "kubernetes-1-28-eks-37"
228+
},
229+
"eksa": "someValue"
230+
}],
231+
"otherField": "otherValue"
232+
}
233+
}`,
234+
expectErrSubstr: "",
235+
expectExclude: []string{
236+
"creationTimestamp",
237+
"annotations",
238+
"status",
239+
"eksa",
240+
},
241+
expectInclude: []string{
242+
"kubeVersion",
243+
"endOfExtendedSupport",
244+
"eksD",
245+
},
246+
},
247+
{
248+
testName: "Invalid JSON payload",
249+
jsonPayload: `{"unclosed": [`,
250+
expectErrSubstr: "unmarshalling JSON:",
251+
},
252+
{
253+
testName: "Excludes with minimal JSON",
254+
jsonPayload: `{
255+
"metadata": {"creationTimestamp": "2021-09-01T00:00:00Z"},
256+
"spec": {
257+
"versionsBundles": [{
258+
"kubeVersion": "1.31"
259+
}]
260+
}
261+
}`,
262+
expectErrSubstr: "",
263+
expectExclude: []string{"creationTimestamp"},
264+
expectInclude: []string{"spec"},
265+
},
266+
}
267+
268+
for _, tt := range testCases {
269+
t.Run(tt.testName, func(t *testing.T) {
270+
g := NewWithT(t)
271+
272+
filtered, err := filterExcludes([]byte(tt.jsonPayload))
273+
274+
if tt.expectErrSubstr == "" {
275+
g.Expect(err).NotTo(HaveOccurred(),
276+
"Expected success but got error: %v", err)
277+
g.Expect(filtered).NotTo(BeEmpty(), "Expected non-empty filtered output")
278+
279+
// Convert filtered output back to string for substring checks
280+
filteredStr := string(filtered)
281+
for _, excl := range tt.expectExclude {
282+
g.Expect(filteredStr).NotTo(ContainSubstring(excl),
283+
"Expected %q to be excluded but it was present", excl)
284+
}
285+
for _, incl := range tt.expectInclude {
286+
g.Expect(filteredStr).To(ContainSubstring(incl),
287+
"Expected %q to be included but it was not found", incl)
288+
}
289+
} else {
290+
g.Expect(err).To(HaveOccurred(),
291+
"Expected error but got none")
292+
g.Expect(err.Error()).To(ContainSubstring(tt.expectErrSubstr),
293+
"Error should contain substring %q", tt.expectErrSubstr)
294+
}
295+
})
296+
}
297+
}

0 commit comments

Comments
 (0)