From c1c65381c14cec058d902a291bc66f83a72f3769 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Tue, 25 Oct 2016 16:37:40 +0800 Subject: [PATCH] Add manifestlist validation Signed-off-by: zhouhao --- image/image.go | 13 +++++++ image/manifest_list.go | 80 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 image/manifest_list.go diff --git a/image/image.go b/image/image.go index 1551c1c..b3c008d 100644 --- a/image/image.go +++ b/image/image.go @@ -20,6 +20,7 @@ import ( "log" "os" "path/filepath" + "strings" "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -87,6 +88,18 @@ func validate(w walker, refs []string, out *log.Logger) error { if err := m.validate(w); err != nil { return err } + + ml, err := findManifestList(w, d) + if err == nil { + if err := ml.validate(w); err != nil { + return err + } + } else { + if !strings.Contains(err, "manifestlist not found") { + return err + } + } + if out != nil { out.Printf("reference %q: OK", ref) } diff --git a/image/manifest_list.go b/image/manifest_list.go new file mode 100644 index 0000000..e34917f --- /dev/null +++ b/image/manifest_list.go @@ -0,0 +1,80 @@ +// Copyright 2016 The Linux Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package image + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + + "github.com/opencontainers/image-spec/schema" + "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" +) + +type manifestlist struct { + Manifests []ManifestDescriptor `json:"manifests"` +} +type ManifestDescriptor struct { + Config descriptor +} + +func findManifestList(w walker, d *descriptor) (*manifestlist, error) { + var ml manifestlist + mlpath := filepath.Join("blobs", d.algo(), d.hash()) + + switch err := w.walk(func(path string, info os.FileInfo, r io.Reader) error { + if info.IsDir() || filepath.Clean(path) != mlpath { + return nil + } + + buf, err := ioutil.ReadAll(r) + if err != nil { + return errors.Wrapf(err, "%s: error reading manifestlist", path) + } + + if err := schema.MediaTypeManifestList.Validate(bytes.NewReader(buf)); err != nil { + return errors.Wrapf(err, "%s: manifestlist validation failed", path) + } + + if err := json.Unmarshal(buf, &ml); err != nil { + return err + } + + if len(ml.Manifests) == 0 { + return fmt.Errorf("%s: no manifests found", path) + } + + return errEOW + }); err { + case nil: + return nil, fmt.Errorf("%s: manifestlist not found", mlpath) + case errEOW: + return &ml, nil + default: + return nil, err + } +} + +func (ml *manifestlist) validate(w walker) error { + for _, d := range ml.Manifests { + if err := d.Config.validate(w, []string{v1.MediaTypeImageConfig}); err != nil { + return errors.Wrap(err, "Descriptor validation failed") + } + } + + return nil +}