...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package platform
16
17 import (
18 "fmt"
19 "strings"
20
21 v1 "github.com/google/go-containerregistry/pkg/v1"
22 "github.com/sigstore/cosign/v2/pkg/oci"
23 )
24
25 type List []struct {
26 Hash v1.Hash
27 Platform *v1.Platform
28 }
29
30 func (pl *List) String() string {
31 r := []string{}
32 for _, p := range *pl {
33 r = append(r, p.Platform.String())
34 }
35 return strings.Join(r, ", ")
36 }
37
38 func GetIndexPlatforms(idx oci.SignedImageIndex) (List, error) {
39 im, err := idx.IndexManifest()
40 if err != nil {
41 return nil, fmt.Errorf("fetching index manifest: %w", err)
42 }
43
44 platforms := List{}
45 for _, m := range im.Manifests {
46 if m.Platform == nil {
47 continue
48 }
49 platforms = append(platforms, struct {
50 Hash v1.Hash
51 Platform *v1.Platform
52 }{m.Digest, m.Platform})
53 }
54 return platforms, nil
55 }
56
57
58
59
60 func matchPlatform(base *v1.Platform, list List) List {
61 ret := List{}
62 for _, p := range list {
63 if base.OS != "" && base.OS != p.Platform.OS {
64 continue
65 }
66 if base.Architecture != "" && base.Architecture != p.Platform.Architecture {
67 continue
68 }
69 if base.Variant != "" && base.Variant != p.Platform.Variant {
70 continue
71 }
72
73 if base.OSVersion != "" && p.Platform.OSVersion != base.OSVersion {
74 if base.OS != "windows" {
75 continue
76 } else {
77 if pcount, bcount := strings.Count(base.OSVersion, "."), strings.Count(p.Platform.OSVersion, "."); pcount == 2 && bcount == 3 {
78 if base.OSVersion != p.Platform.OSVersion[:strings.LastIndex(p.Platform.OSVersion, ".")] {
79 continue
80 }
81 } else {
82 continue
83 }
84 }
85 }
86 ret = append(ret, p)
87 }
88
89 return ret
90 }
91
92 func SignedEntityForPlatform(se oci.SignedEntity, platform string) (oci.SignedEntity, error) {
93 if platform == "" {
94
95 return se, nil
96 }
97 idx, isIndex := se.(oci.SignedImageIndex)
98
99
100 if !isIndex {
101 return nil, fmt.Errorf("specified reference is not a multiarch image")
102 }
103
104 targetPlatform, err := v1.ParsePlatform(platform)
105 if err != nil {
106 return nil, fmt.Errorf("parsing platform: %w", err)
107 }
108 platforms, err := GetIndexPlatforms(idx)
109 if err != nil {
110 return nil, fmt.Errorf("getting available platforms: %w", err)
111 }
112
113 platforms = matchPlatform(targetPlatform, platforms)
114 if len(platforms) == 0 {
115 return nil, fmt.Errorf("unable to find an entity for %s", targetPlatform.String())
116 }
117 if len(platforms) > 1 {
118 return nil, fmt.Errorf(
119 "platform spec matches more than one image architecture: %s",
120 platforms.String(),
121 )
122 }
123
124 nse, err := idx.SignedImage(platforms[0].Hash)
125 if err != nil {
126 return nil, fmt.Errorf("searching for %s image: %w", platforms[0].Hash.String(), err)
127 }
128 if nse == nil {
129 return nil, fmt.Errorf("unable to find image %s", platforms[0].Hash.String())
130 }
131
132 return nse, nil
133 }
134
View as plain text