...
1 package validate
2
3 import (
4 "fmt"
5
6 v1 "github.com/google/go-containerregistry/pkg/v1"
7
8 wh "edge-infra.dev/pkg/f8n/warehouse"
9 "edge-infra.dev/pkg/f8n/warehouse/oci"
10 "edge-infra.dev/pkg/f8n/warehouse/oci/layer"
11 )
12
13
14
15
16
17
18 func Validate(a oci.Artifact, fns *Fns) error {
19 rootAnnotations, err := oci.Annotations(a)
20 if err != nil {
21 return err
22 }
23
24 switch t := a.(type) {
25 case oci.Unwrapper:
26 return Validate(t.Unwrap(), fns)
27 case v1.ImageIndex:
28 return fns.validateIndex(t, rootAnnotations)
29 case v1.Image:
30 return fns.validateImage(t, rootAnnotations)
31 default:
32 return oci.ErrInvalidArtifact
33 }
34 }
35
36
37
38
39
40
41
42
43
44
45 type Fns struct {
46 Index func(idx oci.Artifact, rootAnnotations map[string]string) error
47 Image func(img oci.Artifact, rootAnnotations map[string]string) error
48 Layer func(l layer.Layer, rootAnnotations map[string]string) error
49 }
50
51 func (f *Fns) validateIndex(idx oci.Artifact, rootAnnotations map[string]string) error {
52 i := idx.(v1.ImageIndex)
53
54 m, err := i.IndexManifest()
55 if err != nil {
56 return err
57 }
58
59 for n, desc := range m.Manifests {
60 switch {
61 case desc.MediaType.IsIndex():
62 var ii v1.ImageIndex
63 ii, err = i.ImageIndex(desc.Digest)
64 if err == nil {
65 err = f.validateIndex(ii, rootAnnotations)
66 }
67 case desc.MediaType.IsImage():
68 var im v1.Image
69 im, err = i.Image(desc.Digest)
70 if err == nil {
71 err = f.validateImage(im, rootAnnotations)
72 }
73 default:
74 err = oci.ErrInvalidArtifact
75 }
76
77 if err != nil {
78 return fmt.Errorf("descriptor %d is invalid: %v", n, err)
79 }
80 }
81
82 return f.indexValidator(idx, rootAnnotations)
83 }
84
85 func (f *Fns) validateImage(img oci.Artifact, rootAnnotations map[string]string) error {
86 i := img.(v1.Image)
87
88 layers, err := layer.FromImage(i)
89 if err != nil {
90 return err
91 }
92
93 for n, layer := range layers {
94 if err := f.layerValidator(layer, rootAnnotations); err != nil {
95 return fmt.Errorf("layer %d is invalid: %v", n, err)
96 }
97 }
98
99 return f.imageValidator(img, rootAnnotations)
100 }
101
102
103 func (f *Fns) indexValidator(idx oci.Artifact, rootAnnotations map[string]string) error {
104 if f.Index != nil {
105 if err := f.Index(idx, rootAnnotations); err != nil {
106 name := artifactName(idx)
107 if name != "" {
108 return fmt.Errorf("'%s' is invalid v1.ImageIndex: %v", name, err)
109 }
110 return fmt.Errorf("invalid v1.ImageIndex: %v", err)
111 }
112 }
113 return nil
114 }
115
116
117 func (f *Fns) imageValidator(img oci.Artifact, rootAnnotations map[string]string) error {
118 if f.Image != nil {
119 if err := f.Image(img, rootAnnotations); err != nil {
120 name := artifactName(img)
121 if name != "" {
122 return fmt.Errorf("'%s' is invalid v1.Image: %v", name, err)
123 }
124 return fmt.Errorf("invalid v1.Image: %v", err)
125 }
126 }
127 return nil
128 }
129
130
131 func (f *Fns) layerValidator(l layer.Layer, rootAnnotations map[string]string) error {
132 if f.Layer != nil {
133 if err := f.Layer(l, rootAnnotations); err != nil {
134 return fmt.Errorf("invalid v1.Layer: %v", err)
135 }
136 }
137 return nil
138 }
139
140
141 func artifactName(a oci.Artifact) string {
142 annos, err := oci.Annotations(a)
143 if err != nil {
144 return ""
145 }
146 name, ok := annos[wh.AnnotationName]
147 if !ok {
148 return ""
149 }
150 return name
151 }
152
View as plain text