@@ -14,10 +14,12 @@ import (
14
14
"github.com/flashbots/gh-artifacts-sync/utils"
15
15
"go.uber.org/zap"
16
16
17
+ crauthn "github.com/google/go-containerregistry/pkg/authn"
17
18
crname "github.com/google/go-containerregistry/pkg/name"
18
19
cr "github.com/google/go-containerregistry/pkg/v1"
19
20
crempty "github.com/google/go-containerregistry/pkg/v1/empty"
20
21
crmutate "github.com/google/go-containerregistry/pkg/v1/mutate"
22
+ crremote "github.com/google/go-containerregistry/pkg/v1/remote"
21
23
crtarball "github.com/google/go-containerregistry/pkg/v1/tarball"
22
24
)
23
25
@@ -28,45 +30,60 @@ type container struct {
28
30
manifest * cr.Manifest
29
31
}
30
32
31
- func (s * Server ) prepareIndexManifestForDestination (
33
+ func (s * Server ) dockerExtractImagesAndAttestations (
32
34
indexManifest * cr.IndexManifest ,
33
- dst * config.Destination ,
34
- ) error {
35
- if indexManifest == nil || dst == nil {
36
- return nil
35
+ ) (images map [string ]* cr.Descriptor , attestations map [string ]* cr.Descriptor , err error ) {
36
+ if indexManifest == nil {
37
+ return nil , nil , nil
37
38
}
38
39
39
- var (
40
- attestations = make (map [string ]* cr.Descriptor , 0 )
41
- images = make (map [string ]* cr.Descriptor , 0 )
42
- errs = make ([]error , 0 )
43
- )
40
+ images = make (map [string ]* cr.Descriptor , 0 )
41
+ attestations = make (map [string ]* cr.Descriptor , 0 )
44
42
45
- { // separate images from their respective attestations
46
- for _ , desc := range indexManifest .Manifests {
47
- if desc .Annotations ["vnd.docker.reference.type" ] != "attestation-manifest" {
48
- images [desc .Digest .String ()] = & desc
49
- continue
50
- }
43
+ errs := make ([] error , 0 )
44
+ for _ , desc := range indexManifest .Manifests {
45
+ if desc .Annotations ["vnd.docker.reference.type" ] != "attestation-manifest" {
46
+ images [desc .Digest .String ()] = & desc
47
+ continue
48
+ }
51
49
52
- digest := desc .Annotations ["vnd.docker.reference.digest" ]
53
- if digest == "" {
54
- err := fmt .Errorf ("index contains reference w/o digest: %s" ,
55
- desc .Digest .String (),
56
- )
57
- errs = append (errs , err )
58
- continue
59
- }
50
+ digest := desc .Annotations ["vnd.docker.reference.digest" ]
51
+ if digest == "" {
52
+ err := fmt .Errorf ("index contains reference w/o digest: %s" ,
53
+ desc .Digest .String (),
54
+ )
55
+ errs = append (errs , err )
56
+ continue
57
+ }
60
58
61
- if another , collision := attestations [digest ]; collision {
62
- err := fmt .Errorf ("index contains multiple attestations for the same reference: %s: %s vs. %s" ,
63
- digest , desc .Digest .String (), another .Digest .String (),
64
- )
65
- errs = append (errs , err )
66
- continue
67
- }
59
+ if another , collision := attestations [digest ]; collision {
60
+ err := fmt .Errorf ("index contains multiple attestations for the same reference: %s: %s vs. %s" ,
61
+ digest , desc .Digest .String (), another .Digest .String (),
62
+ )
63
+ errs = append (errs , err )
64
+ continue
65
+ }
66
+
67
+ attestations [digest ] = & desc
68
+ }
69
+
70
+ return images , attestations , utils .FlattenErrors (errs )
71
+ }
72
+
73
+ func (s * Server ) dockerFilterIndexManifest (
74
+ indexManifest * cr.IndexManifest ,
75
+ dst * config.Destination ,
76
+ ) error {
77
+ var (
78
+ attestations map [string ]* cr.Descriptor
79
+ images map [string ]* cr.Descriptor
80
+ err error
81
+ )
68
82
69
- attestations [digest ] = & desc
83
+ { // separate images from their respective attestations
84
+ images , attestations , err = s .dockerExtractImagesAndAttestations (indexManifest )
85
+ if len (images ) == 0 && len (attestations ) == 0 {
86
+ return err
70
87
}
71
88
}
72
89
@@ -87,10 +104,10 @@ func (s *Server) prepareIndexManifestForDestination(
87
104
}
88
105
}
89
106
90
- return utils . FlattenErrors ( errs )
107
+ return nil
91
108
}
92
109
93
- func (s * Server ) prepareImageForUpload (
110
+ func (s * Server ) dockerPrepareImage (
94
111
ctx context.Context ,
95
112
j job.UploadableContainer ,
96
113
stream * zip.ReadCloser ,
@@ -131,7 +148,7 @@ func (s *Server) prepareImageForUpload(
131
148
}
132
149
133
150
case ".tar" :
134
- image , err := crtarball .Image (zipFileOpener (f ), nil )
151
+ image , err := crtarball .Image (helperZipFileOpener (f ), nil )
135
152
if err != nil {
136
153
l .Error ("Failed to open container tarball" , zap .Error (err ))
137
154
errs = append (errs , err )
@@ -172,7 +189,7 @@ func (s *Server) prepareImageForUpload(
172
189
}
173
190
}
174
191
175
- { // filter platforms
192
+ { // filter by platform
176
193
switch indexManifest {
177
194
case nil :
178
195
for originalDigest , container := range containers {
@@ -182,7 +199,7 @@ func (s *Server) prepareImageForUpload(
182
199
}
183
200
184
201
default :
185
- if err := s .prepareIndexManifestForDestination (indexManifest , dst ); err != nil {
202
+ if err := s .dockerFilterIndexManifest (indexManifest , dst ); err != nil {
186
203
errs = append (errs , err )
187
204
}
188
205
_containers := make (map [string ]* container )
@@ -194,6 +211,7 @@ func (s *Server) prepareImageForUpload(
194
211
containers = _containers
195
212
}
196
213
}
214
+
197
215
if len (containers ) == 0 {
198
216
l .Info ("No matching platforms, skipping..." )
199
217
return nil , nil , nil , utils .FlattenErrors (errs )
@@ -223,29 +241,138 @@ func (s *Server) prepareImageForUpload(
223
241
}
224
242
225
243
var index cr.ImageIndex = crempty .Index
226
- for _ , desc := range indexManifest .Manifests {
227
- originalDigest := desc .Digest .String ()
228
- container := containers [originalDigest ]
229
- annotations := desc .Annotations
230
-
231
- if annotations ["vnd.docker.reference.type" ] == "attestation-manifest" {
232
- if annotationOriginalDigest , ok := annotations ["vnd.docker.reference.digest" ]; ok {
233
- if reference , ok := containers [annotationOriginalDigest ]; ok {
234
- annotations ["vnd.docker.reference.digest" ] = reference .digest .String ()
244
+ { // prepare container index
245
+ for _ , desc := range indexManifest .Manifests {
246
+ originalDigest := desc .Digest .String ()
247
+ container := containers [originalDigest ]
248
+ annotations := desc .Annotations
249
+
250
+ if annotations ["vnd.docker.reference.type" ] == "attestation-manifest" {
251
+ if originalReferenceDigest , ok := annotations ["vnd.docker.reference.digest" ]; ok {
252
+ if reference , ok := containers [originalReferenceDigest ]; ok {
253
+ annotations ["vnd.docker.reference.digest" ] = reference .digest .String ()
254
+ }
235
255
}
236
256
}
257
+
258
+ index = crmutate .AppendManifests (index , crmutate.IndexAddendum {
259
+ Add : container .image ,
260
+
261
+ Descriptor : cr.Descriptor {
262
+ Annotations : annotations ,
263
+ Digest : container .digest ,
264
+ Platform : container .config .Platform (),
265
+ },
266
+ })
237
267
}
268
+ }
269
+ return ref , nil , index , utils .FlattenErrors (errs )
270
+ }
271
+
272
+ func (s * Server ) dockerTagRemoteSubImages (
273
+ ctx context.Context ,
274
+ ref crname.Reference ,
275
+ auth crauthn.Authenticator ,
276
+ ) error {
277
+ l := logutils .LoggerFromContext (ctx )
238
278
239
- index = crmutate .AppendManifests (index , crmutate.IndexAddendum {
240
- Add : container .image ,
279
+ desc , err := crremote .Get (ref , crremote .WithAuth (auth ))
280
+ if err != nil {
281
+ return fmt .Errorf ("failed to get a descriptor for container image: %s: %w" ,
282
+ ref .Name (), err ,
283
+ )
284
+ }
241
285
242
- Descriptor : cr.Descriptor {
243
- Annotations : annotations ,
244
- Digest : container .digest ,
245
- Platform : container .config .Platform (),
246
- },
247
- })
286
+ if ! desc .MediaType .IsIndex () {
287
+ return nil
248
288
}
249
289
250
- return ref , nil , index , utils .FlattenErrors (errs )
290
+ index , err := crremote .Index (ref , crremote .WithAuth (auth ))
291
+ if err != nil {
292
+ return fmt .Errorf ("failed to retrieve container index: %s: %w" ,
293
+ ref .Name (), err ,
294
+ )
295
+ }
296
+
297
+ indexManifest , err := index .IndexManifest ()
298
+ if err != nil {
299
+ return fmt .Errorf ("failed to get image index manifest from a descriptor: %s: %s: %w" ,
300
+ ref .Name (), desc .Digest .String (), err ,
301
+ )
302
+ }
303
+
304
+ l .Debug ("Downloaded an index" ,
305
+ zap .String ("digest" , desc .Digest .String ()),
306
+ zap .String ("reference" , ref .Name ()),
307
+ zap .Any ("annotations" , indexManifest .Annotations ),
308
+ )
309
+
310
+ images , attestations , err := s .dockerExtractImagesAndAttestations (indexManifest )
311
+ if len (images ) == 0 && len (attestations ) == 0 {
312
+ return err
313
+ }
314
+
315
+ errs := make ([]error , 0 )
316
+ for _ , desc := range images {
317
+ image , err := index .Image (desc .Digest )
318
+ if err != nil {
319
+ errs = append (errs , fmt .Errorf ("failed to get image from an index: %s: %s: %w" ,
320
+ ref .Name (), desc .Digest .String (), err ,
321
+ ))
322
+ continue
323
+ }
324
+
325
+ _tag := fmt .Sprintf ("%s:%s-%s-%s" ,
326
+ ref .Context ().Name (), ref .Identifier (), desc .Platform .OS , desc .Platform .Architecture ,
327
+ )
328
+ tag , err := crname .NewTag (_tag )
329
+ if err != nil {
330
+ errs = append (errs , fmt .Errorf ("failed to parse a tag: %s: %w" ,
331
+ _tag , err ,
332
+ ))
333
+ continue
334
+ }
335
+
336
+ if err := crremote .Tag (tag , image , crremote .WithAuth (auth )); err != nil {
337
+ errs = append (errs , fmt .Errorf ("failed to tag sub-image: %s: %w" ,
338
+ _tag , err ,
339
+ ))
340
+ continue
341
+ }
342
+ }
343
+
344
+ for digest , desc := range attestations {
345
+ reference , ok := images [digest ]
346
+ if ! ok {
347
+ continue
348
+ }
349
+
350
+ image , err := index .Image (desc .Digest )
351
+ if err != nil {
352
+ errs = append (errs , fmt .Errorf ("failed to get image from an index: %s: %s: %w" ,
353
+ ref .Name (), desc .Digest .String (), err ,
354
+ ))
355
+ continue
356
+ }
357
+
358
+ _tag := fmt .Sprintf ("%s:%s-%s-%s-attestation" ,
359
+ ref .Context ().Name (), ref .Identifier (), reference .Platform .OS , reference .Platform .Architecture ,
360
+ )
361
+ tag , err := crname .NewTag (_tag )
362
+ if err != nil {
363
+ errs = append (errs , fmt .Errorf ("failed to parse a tag: %s: %w" ,
364
+ _tag , err ,
365
+ ))
366
+ continue
367
+ }
368
+
369
+ if err := crremote .Tag (tag , image , crremote .WithAuth (auth )); err != nil {
370
+ errs = append (errs , fmt .Errorf ("failed to tag sub-image: %s: %w" ,
371
+ _tag , err ,
372
+ ))
373
+ continue
374
+ }
375
+ }
376
+
377
+ return utils .FlattenErrors (errs )
251
378
}
0 commit comments