1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package mutate
17
18 import (
19 "crypto/rand"
20 "errors"
21 "fmt"
22 "reflect"
23 "testing"
24
25 v1 "github.com/google/go-containerregistry/pkg/v1"
26 "github.com/google/go-containerregistry/pkg/v1/mutate"
27 "github.com/google/go-containerregistry/pkg/v1/random"
28 "github.com/sigstore/cosign/v2/pkg/oci"
29 "github.com/sigstore/cosign/v2/pkg/oci/signed"
30 "github.com/sigstore/cosign/v2/pkg/oci/static"
31 )
32
33 func TestAppendManifests(t *testing.T) {
34 ii, err := random.Index(300 , 3 , 5 )
35 if err != nil {
36 t.Fatalf("random.Index() = %v", err)
37 }
38 i2, err := random.Image(300 , 3 )
39 if err != nil {
40 t.Fatalf("random.Image() = %v", err)
41 }
42 ii3, err := random.Index(300 , 3 , 5 )
43 if err != nil {
44 t.Fatalf("random.Index() = %v", err)
45 }
46 ii = mutate.AppendManifests(ii, mutate.IndexAddendum{
47 Add: i2,
48 }, mutate.IndexAddendum{
49 Add: ii3,
50 })
51 ii2, err := random.Index(300 , 3 , 5 )
52 if err != nil {
53 t.Fatalf("random.Index() = %v", err)
54 }
55 i1, err := random.Image(300 , 3 )
56 if err != nil {
57 t.Fatalf("random.Image() = %v", err)
58 }
59
60 tests := []struct {
61 name string
62 fn func(v1.ImageIndex) v1.ImageIndex
63 }{{
64 name: "unsigned",
65 fn: func(in v1.ImageIndex) v1.ImageIndex {
66 return in
67 },
68 }, {
69 name: "signed",
70 fn: func(in v1.ImageIndex) v1.ImageIndex {
71 return signed.ImageIndex(in)
72 },
73 }}
74
75 for _, test := range tests {
76 t.Run(test.name, func(t *testing.T) {
77 ni := AppendManifests(test.fn(ii), IndexAddendum{
78 Add: signed.Image(i1),
79 }, IndexAddendum{
80 Add: signed.ImageIndex(ii2),
81 })
82 if err != nil {
83 t.Fatalf("AppendManifests() = %v", err)
84 }
85
86 im, err := ni.IndexManifest()
87 if err != nil {
88 t.Fatalf("IndexManifest() = %v", err)
89 }
90
91 if got, want := len(im.Manifests), 7+2; got != want {
92 t.Errorf("len(im.Manifests) = %d, wanted %d", got, want)
93 }
94
95 if sigs, err := ni.Signatures(); err != nil {
96 t.Errorf("Signatures() = %v", err)
97 } else if sl, err := sigs.Get(); err != nil {
98 t.Errorf("Get() = %v", err)
99 } else if len(sl) != 0 {
100 t.Errorf("len(Get()) = %d, wanted 0", len(sl))
101 }
102
103 if atts, err := ni.Attestations(); err != nil {
104 t.Errorf("Attestations() = %v", err)
105 } else if al, err := atts.Get(); err != nil {
106 t.Errorf("Get() = %v", err)
107 } else if len(al) != 0 {
108 t.Errorf("len(Get()) = %d, wanted 0", len(al))
109 }
110
111 d1, err := i1.Digest()
112 if err != nil {
113 t.Fatalf("Digest() = %v", err)
114 }
115 if _, err := ni.SignedImage(d1); err != nil {
116 t.Fatalf("SignedImage() = %v", err)
117 }
118
119 d2, err := ii2.Digest()
120 if err != nil {
121 t.Fatalf("Digest() = %v", err)
122 }
123 if _, err := ni.SignedImageIndex(d2); err != nil {
124 t.Fatalf("SignedImageIndex() = %v", err)
125 }
126
127 if se, err := ni.SignedImage(d2); err == nil {
128 t.Fatalf("SignedImage() = %#v, wanted error", se)
129 }
130 if se, err := ni.SignedImageIndex(d1); err == nil {
131 t.Fatalf("SignedImageIndex() = %#v, wanted error", se)
132 }
133
134 d3, err := i2.Digest()
135 if err != nil {
136 t.Fatalf("Digest() = %v", err)
137 }
138 if _, err := ni.SignedImage(d3); err != nil {
139 t.Fatalf("SignedImage() = %v", err)
140 }
141
142 d4, err := ii3.Digest()
143 if err != nil {
144 t.Fatalf("Digest() = %v", err)
145 }
146 if _, err := ni.SignedImageIndex(d4); err != nil {
147 t.Fatalf("SignedImageIndex() = %v", err)
148 }
149 })
150 }
151 }
152
153 func TestSignEntity(t *testing.T) {
154 i, err := random.Image(300 , 3 )
155 if err != nil {
156 t.Fatalf("random.Image() = %v", err)
157 }
158 si := signed.Image(i)
159
160 ii, err := random.Index(300 , 3 , 5 )
161 if err != nil {
162 t.Fatalf("random.Index() = %v", err)
163 }
164 sii := signed.ImageIndex(ii)
165
166
167
168 want := make([]byte, 300)
169 rand.Read(want)
170 orig, err := static.NewFile(want)
171 if err != nil {
172 t.Fatalf("static.NewFile() = %v", err)
173 }
174 sunk, err := AttachFileToUnknown(sii, "sbom", orig)
175 if err != nil {
176 t.Fatalf("AttachFileToUnknown() = %v", err)
177 }
178
179 t.Run("attach SBOMs", func(t *testing.T) {
180 for _, se := range []oci.SignedEntity{si, sii, sunk} {
181 want := make([]byte, 300)
182 rand.Read(want)
183
184 orig, err := static.NewFile(want)
185 if err != nil {
186 t.Fatalf("static.NewFile() = %v", err)
187 }
188 se, err = AttachFileToEntity(se, "sbom", orig)
189 if err != nil {
190 t.Fatalf("AttachFileToEntity() = %v", err)
191 }
192
193 f, err := se.Attachment("sbom")
194 if err != nil {
195 t.Fatalf("Attachment(sbom) = %v", err)
196 }
197 got, err := f.Payload()
198 if err != nil {
199 t.Fatalf("Payload() = %v", err)
200 }
201 if !reflect.DeepEqual(want, got) {
202 t.Errorf("Payload() = %v, wanted %v", got, want)
203 }
204
205 f, err = se.Attachment("gitbom")
206 if err == nil {
207 t.Errorf("Attachment(gitbom) = %T, wanted error", f)
208 }
209 }
210 })
211
212 t.Run("without duplicate detector (signature)", func(t *testing.T) {
213 for _, se := range []oci.SignedEntity{si, sii, sunk} {
214 orig, err := static.NewSignature(nil, "")
215 if err != nil {
216 t.Fatalf("static.NewSignature() = %v", err)
217 }
218 se, err = AttachSignatureToEntity(se, orig)
219 if err != nil {
220 t.Fatalf("AttachSignatureToEntity() = %v", err)
221 }
222
223 for i := 2; i < 10; i++ {
224 sig, err := static.NewSignature(nil, fmt.Sprintf("%d", i))
225 if err != nil {
226 t.Fatalf("static.NewSignature() = %v", err)
227 }
228
229 se, err = AttachSignatureToEntity(se, sig)
230 if err != nil {
231 t.Fatalf("AttachSignatureToEntity() = %v", err)
232 }
233
234 sigs, err := se.Signatures()
235 if err != nil {
236 t.Fatalf("Signatures() = %v", err)
237 }
238 if sl, err := sigs.Get(); err != nil {
239 t.Fatalf("Get() = %v", err)
240 } else if len(sl) != i {
241 t.Errorf("len(Get()) = %d, wanted %d", len(sl), i)
242 }
243 }
244 }
245 })
246
247 t.Run("without duplicate detector (attestation)", func(t *testing.T) {
248 for _, se := range []oci.SignedEntity{si, sii, sunk} {
249 orig, err := static.NewAttestation([]byte("payload"))
250 if err != nil {
251 t.Fatalf("static.NewAttestation() = %v", err)
252 }
253 se, err = AttachAttestationToEntity(se, orig)
254 if err != nil {
255 t.Fatalf("AttachAttestationToEntity() = %v", err)
256 }
257
258 for i := 2; i < 10; i++ {
259 sig, err := static.NewAttestation([]byte(fmt.Sprintf("%d", i)))
260 if err != nil {
261 t.Fatalf("static.NewAttestation() = %v", err)
262 }
263
264 se, err = AttachAttestationToEntity(se, sig)
265 if err != nil {
266 t.Fatalf("AttachAttestationToEntity() = %v", err)
267 }
268
269 atts, err := se.Attestations()
270 if err != nil {
271 t.Fatalf("Attestations() = %v", err)
272 }
273 if al, err := atts.Get(); err != nil {
274 t.Fatalf("Get() = %v", err)
275 } else if len(al) != i {
276 t.Errorf("len(Get()) = %d, wanted %d", len(al), i)
277 }
278 }
279 }
280 })
281
282 t.Run("with duplicate detector (signature)", func(t *testing.T) {
283 for _, se := range []oci.SignedEntity{si, sii, sunk} {
284 orig, err := static.NewSignature(nil, "")
285 if err != nil {
286 t.Fatalf("static.NewSignature() = %v", err)
287 }
288 se, err = AttachSignatureToEntity(se, orig)
289 if err != nil {
290 t.Fatalf("AttachSignatureToEntity() = %v", err)
291 }
292
293 dd := &dupe{
294 sig: orig,
295 }
296
297 for i := 2; i < 10; i++ {
298 sig, err := static.NewSignature(nil, fmt.Sprintf("%d", i))
299 if err != nil {
300 t.Fatalf("static.NewSignature() = %v", err)
301 }
302
303 se, err = AttachSignatureToEntity(se, sig, WithDupeDetector(dd))
304 if err != nil {
305 t.Fatalf("AttachSignatureToEntity() = %v", err)
306 }
307
308 sigs, err := se.Signatures()
309 if err != nil {
310 t.Fatalf("Signatures() = %v", err)
311 }
312 if sl, err := sigs.Get(); err != nil {
313 t.Fatalf("Get() = %v", err)
314 } else if len(sl) != 1 {
315 t.Errorf("len(Get()) = %d, wanted %d", len(sl), i)
316 }
317 }
318 }
319 })
320
321 t.Run("with duplicate detector (attestation)", func(t *testing.T) {
322 for _, se := range []oci.SignedEntity{si, sii, sunk} {
323 orig, err := static.NewAttestation([]byte("blah"))
324 if err != nil {
325 t.Fatalf("static.NewAttestation() = %v", err)
326 }
327 se, err = AttachAttestationToEntity(se, orig)
328 if err != nil {
329 t.Fatalf("AttachAttestationToEntity() = %v", err)
330 }
331
332 dd := &dupe{
333 sig: orig,
334 }
335
336 for i := 2; i < 10; i++ {
337 sig, err := static.NewAttestation([]byte(fmt.Sprintf("%d", i)))
338 if err != nil {
339 t.Fatalf("static.NewAttestation() = %v", err)
340 }
341
342 se, err = AttachAttestationToEntity(se, sig, WithDupeDetector(dd))
343 if err != nil {
344 t.Fatalf("AttachAttestationToEntity() = %v", err)
345 }
346
347 atts, err := se.Attestations()
348 if err != nil {
349 t.Fatalf("Attestations() = %v", err)
350 }
351 if al, err := atts.Get(); err != nil {
352 t.Fatalf("Get() = %v", err)
353 } else if len(al) != 1 {
354 t.Errorf("len(Get()) = %d, wanted %d", len(al), 1)
355 }
356 }
357 }
358 })
359
360 t.Run("with erroring duplicate detector (signature)", func(t *testing.T) {
361 for _, se := range []oci.SignedEntity{si, sii, sunk} {
362 orig, err := static.NewSignature(nil, "")
363 if err != nil {
364 t.Fatalf("static.NewSignature() = %v", err)
365 }
366 se, err = AttachSignatureToEntity(se, orig)
367 if err != nil {
368 t.Fatalf("AttachSignatureToEntity() = %v", err)
369 }
370
371 want := errors.New("expected error")
372 dd := &dupe{
373 err: want,
374 }
375
376 for i := 2; i < 10; i++ {
377 sig, err := static.NewSignature(nil, fmt.Sprintf("%d", i))
378 if err != nil {
379 t.Fatalf("static.NewSignature() = %v", err)
380 }
381
382 se, err = AttachSignatureToEntity(se, sig, WithDupeDetector(dd))
383 if err != nil {
384 t.Fatalf("AttachSignatureToEntity() = %v", err)
385 }
386
387 if _, got := se.Signatures(); !errors.Is(got, want) {
388 t.Fatalf("Signatures() = %v, wanted %v", got, want)
389 }
390 }
391 }
392 })
393
394 t.Run("with erroring duplicate detector (attestation)", func(t *testing.T) {
395 for _, se := range []oci.SignedEntity{si, sii, sunk} {
396 orig, err := static.NewAttestation([]byte("blah"))
397 if err != nil {
398 t.Fatalf("static.NewAttestation() = %v", err)
399 }
400 se, err = AttachAttestationToEntity(se, orig)
401 if err != nil {
402 t.Fatalf("AttachAttestationToEntity() = %v", err)
403 }
404
405 want := errors.New("expected error")
406 dd := &dupe{
407 err: want,
408 }
409
410 for i := 2; i < 10; i++ {
411 sig, err := static.NewAttestation([]byte(fmt.Sprintf("%d", i)))
412 if err != nil {
413 t.Fatalf("static.NewAttestation() = %v", err)
414 }
415
416 se, err = AttachAttestationToEntity(se, sig, WithDupeDetector(dd))
417 if err != nil {
418 t.Fatalf("AttachAttestationToEntity() = %v", err)
419 }
420
421 if _, got := se.Attestations(); !errors.Is(got, want) {
422 t.Fatalf("Attestations() = %v, wanted %v", got, want)
423 }
424 }
425 }
426 })
427
428 t.Run("with replace op (attestation)", func(t *testing.T) {
429 for _, se := range []oci.SignedEntity{si, sii, sunk} {
430 orig, err := static.NewAttestation([]byte("blah"))
431 if err != nil {
432 t.Fatalf("static.NewAttestation() = %v", err)
433 }
434 se, err = AttachAttestationToEntity(se, orig)
435 if err != nil {
436 t.Fatalf("AttachAttestationToEntity() = %v", err)
437 }
438
439 ro := &replaceAll{}
440
441 for i := 2; i < 10; i++ {
442 sig, err := static.NewAttestation([]byte(fmt.Sprintf("%d", i)))
443 if err != nil {
444 t.Fatalf("static.NewAttestation() = %v", err)
445 }
446
447 se, err = AttachAttestationToEntity(se, sig, WithReplaceOp(ro))
448 if err != nil {
449 t.Fatalf("AttachAttestationToEntity() = %v", err)
450 }
451
452 atts, err := se.Attestations()
453 if err != nil {
454 t.Fatalf("Attestations() = %v", err)
455 }
456 if al, err := atts.Get(); err != nil {
457 t.Fatalf("Get() = %v", err)
458 } else if len(al) != 1 {
459 t.Errorf("len(Get()) = %d, wanted %d", len(al), 1)
460 }
461 }
462 }
463 })
464 }
465
466 type dupe struct {
467 sig oci.Signature
468 err error
469 }
470
471 var _ DupeDetector = (*dupe)(nil)
472
473
474 func (d *dupe) Find(oci.Signatures, oci.Signature) (oci.Signature, error) {
475 return d.sig, d.err
476 }
477
478 type replaceAll struct {
479 }
480
481 func (r *replaceAll) Replace(signatures oci.Signatures, o oci.Signature) (oci.Signatures, error) {
482 return &replaceOCISignatures{
483 Signatures: signatures,
484 attestations: []oci.Signature{o},
485 }, nil
486 }
487
488 type replaceOCISignatures struct {
489 oci.Signatures
490 attestations []oci.Signature
491 }
492
493 func (r *replaceOCISignatures) Get() ([]oci.Signature, error) {
494 return r.attestations, nil
495 }
496
View as plain text