Skip to content

Commit 052ade8

Browse files
author
zhouhao
committed
Add manifestlist validation
Signed-off-by: zhouhao <[email protected]>
1 parent f24d27b commit 052ade8

File tree

3 files changed

+156
-19
lines changed

3 files changed

+156
-19
lines changed

image/image.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,26 @@ func validate(w walker, refs []string, out *log.Logger) error {
7979
return err
8080
}
8181

82-
m, err := findManifest(w, d)
83-
if err != nil {
84-
return err
82+
if d.MediaType == validRefMediaTypes[0] {
83+
m, err := findManifest(w, d)
84+
if err != nil {
85+
return err
86+
}
87+
88+
if err := m.validate(w); err != nil {
89+
return err
90+
}
91+
} else {
92+
ml, err := findManifestList(w, d)
93+
if ml != nil {
94+
if err := ml.validate(w); err != nil {
95+
return err
96+
}
97+
} else if err != nil {
98+
return err
99+
}
85100
}
86101

87-
if err := m.validate(w); err != nil {
88-
return err
89-
}
90102
if out != nil {
91103
out.Printf("reference %q: OK", ref)
92104
}
@@ -129,7 +141,7 @@ func unpack(w walker, dest, refName string) error {
129141
return err
130142
}
131143

132-
if err = m.validate(w); err != nil {
144+
if err := m.validate(w); err != nil {
133145
return err
134146
}
135147

@@ -171,7 +183,7 @@ func createRuntimeBundle(w walker, dest, refName, rootfs string) error {
171183
return err
172184
}
173185

174-
if err = m.validate(w); err != nil {
186+
if err := m.validate(w); err != nil {
175187
return err
176188
}
177189

image/image_test.go

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,23 @@ var (
110110
"mediaType": "application/vnd.oci.image.manifest.v1+json",
111111
"schemaVersion": 2
112112
}
113+
`
114+
manifestlistStr = `{
115+
"schemaVersion": 2,
116+
"mediaType": "application/vnd.oci.image.manifest.list.v1+json",
117+
"manifests": [
118+
{
119+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
120+
"size": "<manifest_size>",
121+
"digest": "<manifest_digest>",
122+
"platform": {
123+
"architecture": "ppc64le",
124+
"os": "linux"
125+
}
126+
}
127+
],
128+
"annotations": null
129+
}
113130
`
114131
)
115132

@@ -119,12 +136,13 @@ type tarContent struct {
119136
}
120137

121138
type imageLayout struct {
122-
rootDir string
123-
layout string
124-
ref string
125-
manifest string
126-
config string
127-
tarList []tarContent
139+
rootDir string
140+
layout string
141+
ref string
142+
manifest string
143+
manifestlist string
144+
config string
145+
tarList []tarContent
128146
}
129147

130148
func TestValidateLayout(t *testing.T) {
@@ -135,11 +153,12 @@ func TestValidateLayout(t *testing.T) {
135153
defer os.RemoveAll(root)
136154

137155
il := imageLayout{
138-
rootDir: root,
139-
layout: layoutStr,
140-
ref: refTag,
141-
manifest: manifestStr,
142-
config: configStr,
156+
rootDir: root,
157+
layout: layoutStr,
158+
ref: refTag,
159+
manifest: manifestStr,
160+
manifestlist: manifestlistStr,
161+
config: configStr,
143162
tarList: []tarContent{
144163
tarContent{&tar.Header{Name: "test", Size: 4, Mode: 0600}, []byte("test")},
145164
},
@@ -195,6 +214,12 @@ func createImageLayoutBundle(il imageLayout) error {
195214
return err
196215
}
197216

217+
// create manifestlist blob file
218+
desc, err = createManifestListFile(il.rootDir, il.manifestlist)
219+
if err != nil {
220+
return err
221+
}
222+
198223
return createRefFile(il.rootDir, il.ref, desc)
199224
}
200225

@@ -238,6 +263,23 @@ func createManifestFile(root, str string) (descriptor, error) {
238263
return createHashedBlob(name)
239264
}
240265

266+
267+
func createManifestListFile(root, str string) (descriptor, error) {
268+
name := filepath.Join(root, "blobs", "sha256", "test-manifestlist")
269+
f, err := os.Create(name)
270+
if err != nil {
271+
return descriptor{}, err
272+
}
273+
defer f.Close()
274+
275+
_, err = io.Copy(f, bytes.NewBuffer([]byte(str)))
276+
if err != nil {
277+
return descriptor{}, err
278+
}
279+
280+
return createHashedBlob(name)
281+
}
282+
241283
func createConfigFile(root, config string) (descriptor, error) {
242284
name := filepath.Join(root, "blobs", "sha256", "test-config")
243285
f, err := os.Create(name)

image/manifest_list.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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 image
16+
17+
import (
18+
"bytes"
19+
"encoding/json"
20+
"fmt"
21+
"io"
22+
"io/ioutil"
23+
"os"
24+
"path/filepath"
25+
26+
"github.com/opencontainers/image-spec/schema"
27+
"github.com/opencontainers/image-spec/specs-go/v1"
28+
"github.com/pkg/errors"
29+
)
30+
31+
type manifestlist struct {
32+
Manifests []ManifestDescriptor `json:"manifests"`
33+
}
34+
type ManifestDescriptor struct {
35+
Manifest descriptor
36+
}
37+
38+
func findManifestList(w walker, d *descriptor) (*manifestlist, error) {
39+
var ml manifestlist
40+
mlpath := filepath.Join("blobs", d.algo(), d.hash())
41+
42+
switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error {
43+
if info.IsDir() || filepath.Clean(path) != mlpath {
44+
return nil
45+
}
46+
47+
buf, err := ioutil.ReadAll(r)
48+
if err != nil {
49+
return errors.Wrapf(err, "%s: error reading manifestlist", path)
50+
}
51+
52+
if err := schema.MediaTypeManifestList.Validate(bytes.NewReader(buf)); err != nil {
53+
return errors.Wrapf(err, "%s: manifestlist validation failed", path)
54+
}
55+
56+
if err := json.Unmarshal(buf, &ml); err != nil {
57+
return err
58+
}
59+
60+
if len(ml.Manifests) == 0 {
61+
return fmt.Errorf("%s: no manifests found", path)
62+
}
63+
64+
return errEOW
65+
}); err {
66+
case nil:
67+
return nil, nil
68+
case errEOW:
69+
return &ml, nil
70+
default:
71+
return nil, err
72+
}
73+
}
74+
75+
func (ml *manifestlist) validate(w walker) error {
76+
for _, d := range ml.Manifests {
77+
if err := d.Manifest.validate(w, []string{v1.MediaTypeImageManifest}); err != nil {
78+
return errors.Wrap(err, "Manifest validation failed")
79+
}
80+
}
81+
82+
return nil
83+
}

0 commit comments

Comments
 (0)