Skip to content

Commit 3ad5d1b

Browse files
author
xiekeyang
committed
Support different levels validation for JSON reader stream
This establishes function list, to allow consumer to select items for validation. A based validation level is JSON schema, and a optional item is the media-type of their referenced fields. Signed-off-by: xiekeyang <[email protected]>
1 parent 0ecc46b commit 3ad5d1b

File tree

7 files changed

+84
-27
lines changed

7 files changed

+84
-27
lines changed

schema/backwards_compatibility_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func TestBackwardsCompatibilityImageIndex(t *testing.T) {
116116

117117
imageIndex := convertFormats(tt.imageIndex)
118118
r := strings.NewReader(imageIndex)
119-
err := schema.ValidatorMediaTypeImageIndex.Validate(r)
119+
err := schema.ValidatorMediaTypeImageIndex.Validate(r, []schema.ValidateFunc{schema.ValidateSchema})
120120

121121
if got := err != nil; tt.fail != got {
122122
t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err)
@@ -178,7 +178,7 @@ func TestBackwardsCompatibilityManifest(t *testing.T) {
178178

179179
manifest := convertFormats(tt.manifest)
180180
r := strings.NewReader(manifest)
181-
err := schema.ValidatorMediaTypeManifest.Validate(r)
181+
err := schema.ValidatorMediaTypeManifest.Validate(r, []schema.ValidateFunc{schema.ValidateSchema})
182182

183183
if got := err != nil; tt.fail != got {
184184
t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err)
@@ -217,7 +217,7 @@ func TestBackwardsCompatibilityConfig(t *testing.T) {
217217

218218
config := convertFormats(tt.config)
219219
r := strings.NewReader(config)
220-
err := schema.ValidatorMediaTypeImageConfig.Validate(r)
220+
err := schema.ValidatorMediaTypeImageConfig.Validate(r, []schema.ValidateFunc{schema.ValidateSchema})
221221

222222
if got := err != nil; tt.fail != got {
223223
t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err)

schema/config_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ func TestConfig(t *testing.T) {
211211
},
212212
} {
213213
r := strings.NewReader(tt.config)
214-
err := schema.ValidatorMediaTypeImageConfig.Validate(r)
214+
err := schema.ValidatorMediaTypeImageConfig.Validate(r, []schema.ValidateFunc{schema.ValidateSchema})
215215

216216
if got := err != nil; tt.fail != got {
217217
t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err)

schema/descriptor_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ func TestDescriptor(t *testing.T) {
204204
},
205205
} {
206206
r := strings.NewReader(tt.descriptor)
207-
err := schema.ValidatorMediaTypeDescriptor.Validate(r)
207+
err := schema.ValidatorMediaTypeDescriptor.Validate(r, []schema.ValidateFunc{schema.ValidateSchema})
208208

209209
if got := err != nil; tt.fail != got {
210210
t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err)

schema/imageindex_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ func TestImageIndex(t *testing.T) {
239239
},
240240
} {
241241
r := strings.NewReader(tt.imageIndex)
242-
err := schema.ValidatorMediaTypeImageIndex.Validate(r)
242+
err := schema.ValidatorMediaTypeImageIndex.Validate(r, []schema.ValidateFunc{schema.ValidateSchema})
243243

244244
if got := err != nil; tt.fail != got {
245245
t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err)

schema/manifest_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func TestManifest(t *testing.T) {
193193
},
194194
} {
195195
r := strings.NewReader(tt.manifest)
196-
err := schema.ValidatorMediaTypeManifest.Validate(r)
196+
err := schema.ValidatorMediaTypeManifest.Validate(r, []schema.ValidateFunc{schema.ValidateSchema})
197197

198198
if got := err != nil; tt.fail != got {
199199
t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err)

schema/spec_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ func validate(t *testing.T, name string) {
7777
continue
7878
}
7979

80-
err = schema.Validator(example.Mediatype).Validate(strings.NewReader(example.Body))
80+
err = schema.Validator(example.Mediatype).Validate(strings.NewReader(example.Body),
81+
[]schema.ValidateFunc{schema.ValidateSchema, schema.ValidateRefMedia})
8182
if err == nil {
8283
printFields(t, "ok", example.Mediatype, example.Title)
8384
t.Log(example.Body, "---")

schema/validator.go

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,42 @@ import (
2626
"github.com/xeipuuv/gojsonschema"
2727
)
2828

29+
type validateRefMediaFunc func(r io.Reader) error
30+
31+
var vlidateRefMediaMap = map[Validator]validateRefMediaFunc{
32+
ValidatorMediaTypeImageIndex: validateImageIndexRefObject,
33+
ValidatorMediaTypeManifest: validateManifestRefObject,
34+
}
35+
36+
// ValidateFunc provides the type of function to validate specific object.
37+
type ValidateFunc func(r io.Reader, v Validator) error
38+
2939
// Validator wraps a media type string identifier
3040
// and implements validation against a JSON schema.
3141
type Validator string
3242

33-
type validateDescendantsFunc func(r io.Reader) error
43+
// Validate validates the given reader against the schema and OCI format defined in spec.
44+
// r: the given reader.
45+
// funcList: the optional functions to validate the wrapped media type.
46+
func (v Validator) Validate(r io.Reader, funcList []ValidateFunc) error {
47+
buf, err := ioutil.ReadAll(r)
48+
if err != nil {
49+
return errors.Wrap(err, "unable to read the document file")
50+
}
51+
52+
for _, f := range funcList {
53+
err := f(bytes.NewReader(buf), v)
54+
if err != nil {
55+
return err
56+
}
57+
}
58+
return nil
59+
}
60+
61+
type unimplemented string
3462

35-
var mapValidateDescendants = map[Validator]validateDescendantsFunc{
36-
ValidatorMediaTypeManifest: validateManifestDescendants,
63+
func (v unimplemented) Validate(src io.Reader) error {
64+
return fmt.Errorf("%s: unimplemented", v)
3765
}
3866

3967
// ValidationError contains all the errors that happened during validation.
@@ -45,23 +73,15 @@ func (e ValidationError) Error() string {
4573
return fmt.Sprintf("%v", e.Errs)
4674
}
4775

48-
// Validate validates the given reader against the schema of the wrapped media type.
49-
func (v Validator) Validate(src io.Reader) error {
76+
// ValidateSchema validates the given reader against the schema of the wrapped media type.
77+
// src: the given reader.
78+
// v: the expected media type.
79+
func ValidateSchema(src io.Reader, v Validator) error {
5080
buf, err := ioutil.ReadAll(src)
5181
if err != nil {
5282
return errors.Wrap(err, "unable to read the document file")
5383
}
5484

55-
if f, ok := mapValidateDescendants[v]; ok {
56-
if f == nil {
57-
return fmt.Errorf("internal error: mapValidateDescendents[%q] is nil", v)
58-
}
59-
err = f(bytes.NewReader(buf))
60-
if err != nil {
61-
return err
62-
}
63-
}
64-
6585
sl := gojsonschema.NewReferenceLoaderFileSystem("file:///"+specs[v], fs)
6686
ml := gojsonschema.NewStringLoader(string(buf))
6787

@@ -86,13 +106,28 @@ func (v Validator) Validate(src io.Reader) error {
86106
}
87107
}
88108

89-
type unimplemented string
109+
// ValidateRefMedia validates the referenced objects against OCI media type defined in spec.
110+
// r: the given reader.
111+
// v: the expected media type.
112+
func ValidateRefMedia(r io.Reader, v Validator) error {
113+
f, ok := vlidateRefMediaMap[v]
114+
if ok {
115+
if f == nil {
116+
return fmt.Errorf("referenced media type validation %q unimplemented", v)
117+
}
90118

91-
func (v unimplemented) Validate(src io.Reader) error {
92-
return fmt.Errorf("%s: unimplemented", v)
119+
buf, err := ioutil.ReadAll(r)
120+
if err != nil {
121+
return errors.Wrap(err, "unable to read the document file")
122+
}
123+
124+
return f(bytes.NewReader(buf))
125+
}
126+
127+
return nil
93128
}
94129

95-
func validateManifestDescendants(r io.Reader) error {
130+
func validateManifestRefObject(r io.Reader) error {
96131
header := v1.Manifest{}
97132

98133
buf, err := ioutil.ReadAll(r)
@@ -117,3 +152,24 @@ func validateManifestDescendants(r io.Reader) error {
117152
}
118153
return nil
119154
}
155+
156+
func validateImageIndexRefObject(r io.Reader) error {
157+
header := v1.ImageIndex{}
158+
159+
buf, err := ioutil.ReadAll(r)
160+
if err != nil {
161+
return errors.Wrapf(err, "error reading the io stream")
162+
}
163+
164+
err = json.Unmarshal(buf, &header)
165+
if err != nil {
166+
return errors.Wrap(err, "manifest list format mismatch")
167+
}
168+
169+
for _, manifest := range header.Manifests {
170+
if manifest.MediaType != string(v1.MediaTypeImageManifest) {
171+
return fmt.Errorf("manifest %s has an unknown media type: %s", manifest.Digest, manifest.MediaType)
172+
}
173+
}
174+
return nil
175+
}

0 commit comments

Comments
 (0)