Skip to content

Commit 1760050

Browse files
committed
schema: Add schema and test for artifact manifest
Signed-off-by: Sajay Antony <[email protected]>
1 parent f9ca252 commit 1760050

File tree

5 files changed

+203
-0
lines changed

5 files changed

+203
-0
lines changed

schema/artifact-manifest-schema.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"description": "OpenContainer Artifact Manifest Specification",
3+
"$schema": "http://json-schema.org/draft-04/schema#",
4+
"id": "https://opencontainers.org/schema/artifact",
5+
"type": "object",
6+
"properties": {
7+
"mediaType": {
8+
"description": "the mediatype of the referenced object",
9+
"$ref": "defs-descriptor.json#/definitions/mediaType"
10+
},
11+
"artifactType": {
12+
"description": "The IANA mediatype of the referenced objects properties",
13+
"$ref": "defs-descriptor.json#/definitions/mediaType"
14+
},
15+
"blobs": {
16+
"type": "array",
17+
"items": {
18+
"$ref": "content-descriptor.json"
19+
}
20+
},
21+
"subject": {
22+
"$ref": "content-descriptor.json"
23+
},
24+
"annotations": {
25+
"id": "https://opencontainers.org/schema/image/manifest/annotations",
26+
"$ref": "defs-descriptor.json#/definitions/annotations"
27+
}
28+
}
29+
}

schema/artifact_test.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// Copyright 2016 The Linux Foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package schema_test
16+
17+
import (
18+
"fmt"
19+
"strings"
20+
"testing"
21+
22+
"github.com/opencontainers/image-spec/schema"
23+
)
24+
25+
func TestArtifact(t *testing.T) {
26+
for i, tt := range []struct {
27+
manifest string
28+
fail bool
29+
}{
30+
// expected failure: mediaType does not match pattern
31+
{
32+
manifest: `
33+
{
34+
"mediaType": "invalid",
35+
"artifactType": "application/example",
36+
"blobs": [
37+
{
38+
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
39+
"size": 148,
40+
"digest": "sha256:c57089565e894899735d458f0fd4bb17a0f1e0df8d72da392b85c9b35ee777cd"
41+
}
42+
]
43+
}
44+
`,
45+
fail: true,
46+
},
47+
48+
// expected failure: invalid artifact mediaType
49+
{
50+
manifest: `
51+
{
52+
"mediaType": "application/vnd.oci.artifact.manifest.v1+json",
53+
"artifactType": "invalid",
54+
"blobs": [
55+
{
56+
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
57+
"size": "148",
58+
"digest": "sha256:c57089565e894899735d458f0fd4bb17a0f1e0df8d72da392b85c9b35ee777cd"
59+
}
60+
]
61+
}
62+
`,
63+
fail: true,
64+
},
65+
66+
// expected failure: blob[0].size is a string, expected integer
67+
{
68+
manifest: `
69+
{
70+
"mediaType": "application/vnd.oci.artifact.manifest.v1+json",
71+
"artifactType": "application/example",
72+
"blobs": [
73+
{
74+
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
75+
"size": "148",
76+
"digest": "sha256:c57089565e894899735d458f0fd4bb17a0f1e0df8d72da392b85c9b35ee777cd"
77+
}
78+
]
79+
}
80+
`,
81+
fail: true,
82+
},
83+
84+
// expected failure: subject: size is required
85+
{
86+
manifest: `
87+
{
88+
"mediaType": "application/vnd.oci.artifact.manifest.v1+json",
89+
"artifactType": "application/example",
90+
"subject": {
91+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
92+
"digest": "sha256:c86f7763873b6c0aae22d963bab59b4f5debbed6685761b5951584f6efb0633b"
93+
},
94+
"annotations": {
95+
"key1": "value1",
96+
"key2": "value2"
97+
}
98+
}
99+
`,
100+
fail: true,
101+
},
102+
103+
// valid manifest with optional fields
104+
{
105+
manifest: `
106+
{
107+
"mediaType": "application/vnd.oci.artifact.manifest.v1+json",
108+
"artifactType": "application/example",
109+
"blobs": [
110+
{
111+
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
112+
"size": 675598,
113+
"digest": "sha256:9d3dd9504c685a304985025df4ed0283e47ac9ffa9bd0326fddf4d59513f0827"
114+
},
115+
{
116+
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
117+
"size": 156,
118+
"digest": "sha256:2b689805fbd00b2db1df73fae47562faac1a626d5f61744bfe29946ecff5d73d"
119+
},
120+
{
121+
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
122+
"size": 148,
123+
"digest": "sha256:c57089565e894899735d458f0fd4bb17a0f1e0df8d72da392b85c9b35ee777cd"
124+
}
125+
],
126+
"subject": {
127+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
128+
"size": 1470,
129+
"digest": "sha256:c86f7763873b6c0aae22d963bab59b4f5debbed6685761b5951584f6efb0633b"
130+
},
131+
"annotations": {
132+
"key1": "value1",
133+
"key2": "value2"
134+
}
135+
}
136+
`,
137+
fail: false,
138+
},
139+
} {
140+
r := strings.NewReader(tt.manifest)
141+
err := schema.ValidatorMediaTypeArtifact.Validate(r)
142+
143+
if got := err != nil; tt.fail != got {
144+
t.Errorf("test %d: expected validation failure %t but got %t, err %v", i, tt.fail, got, err)
145+
fmt.Println(tt.manifest)
146+
}
147+
}
148+
}

schema/schema.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const (
2929
ValidatorMediaTypeImageIndex Validator = v1.MediaTypeImageIndex
3030
ValidatorMediaTypeImageConfig Validator = v1.MediaTypeImageConfig
3131
ValidatorMediaTypeImageLayer unimplemented = v1.MediaTypeImageLayer
32+
ValidatorMediaTypeArtifact Validator = v1.MediaTypeArtifactManifest
3233
)
3334

3435
var (
@@ -68,6 +69,7 @@ var (
6869
ValidatorMediaTypeManifest: "https://opencontainers.org/schema/image/image-manifest-schema.json",
6970
ValidatorMediaTypeImageIndex: "https://opencontainers.org/schema/image/image-index-schema.json",
7071
ValidatorMediaTypeImageConfig: "https://opencontainers.org/schema/image/config-schema.json",
72+
ValidatorMediaTypeArtifact: "https://opencontainers.org/schema/artifact-manifest-schema.json",
7173
}
7274
)
7375

schema/spec_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ func TestValidateConfig(t *testing.T) {
5454
validate(t, "../config.md")
5555
}
5656

57+
func TestValidateArtifactManifest(t *testing.T) {
58+
validate(t, "../artifact.md")
59+
}
60+
5761
func TestSchemaFS(t *testing.T) {
5862
expectedSchemaFileNames, err := filepath.Glob("*.json")
5963
if err != nil {

schema/validator.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ var mapValidate = map[Validator]validateFunc{
3838
ValidatorMediaTypeDescriptor: validateDescriptor,
3939
ValidatorMediaTypeImageIndex: validateIndex,
4040
ValidatorMediaTypeManifest: validateManifest,
41+
ValidatorMediaTypeArtifact: validateArtifact,
4142
}
4243

4344
// ValidationError contains all the errors that happened during validation.
@@ -250,3 +251,22 @@ func checkPlatform(OS string, Architecture string) {
250251
}
251252
fmt.Printf("warning: operating system %q of the bundle is not supported yet.\n", OS)
252253
}
254+
255+
func validateArtifact(r io.Reader) error {
256+
header := v1.Artifact{}
257+
258+
buf, err := io.ReadAll(r)
259+
if err != nil {
260+
return errors.Wrapf(err, "error reading the io stream")
261+
}
262+
263+
err = json.Unmarshal(buf, &header)
264+
if err != nil {
265+
return errors.Wrap(err, "manifest format mismatch")
266+
}
267+
268+
if header.MediaType != string(v1.MediaTypeArtifactManifest) {
269+
fmt.Printf("warning: Artifact has an unknown media type: %s\n", header.MediaType)
270+
}
271+
return nil
272+
}

0 commit comments

Comments
 (0)