```
* use go 1.17 semantics in go.mod
* pin tonistiigi/fsutil dep to match docker/docker's dep
go get -u ./...
go mod vendor
```
This commit is contained in:
Jason Hall
2022-01-21 13:59:16 -05:00
committed by GitHub
parent a59970f4ac
commit 6bbd8a331c
3595 changed files with 429699 additions and 120494 deletions
+41 -4
View File
@@ -18,16 +18,18 @@ import (
"bytes"
"errors"
"fmt"
"io"
"strings"
"github.com/google/go-cmp/cmp"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/partial"
)
// Image validates that img does not violate any invariants of the image format.
func Image(img v1.Image) error {
func Image(img v1.Image, opt ...Option) error {
errs := []string{}
if err := validateLayers(img); err != nil {
if err := validateLayers(img, opt...); err != nil {
errs = append(errs, fmt.Sprintf("validating layers: %v", err))
}
@@ -100,18 +102,34 @@ func validateConfig(img v1.Image) error {
return nil
}
func validateLayers(img v1.Image) error {
func validateLayers(img v1.Image, opt ...Option) error {
o := makeOptions(opt...)
layers, err := img.Layers()
if err != nil {
return err
}
if o.fast {
return layersExist(layers)
}
digests := []v1.Hash{}
diffids := []v1.Hash{}
udiffids := []v1.Hash{}
sizes := []int64{}
for _, layer := range layers {
for i, layer := range layers {
cl, err := computeLayer(layer)
if errors.Is(err, io.ErrUnexpectedEOF) {
// Errored while reading tar content of layer because a header or
// content section was not the correct length. This is most likely
// due to an incomplete download or otherwise interrupted process.
m, err := img.Manifest()
if err != nil {
return fmt.Errorf("undersized layer[%d] content", i)
}
return fmt.Errorf("undersized layer[%d] content: Manifest.Layers[%d].Size=%d", i, i, m.Layers[i].Size)
}
if err != nil {
return err
}
@@ -249,3 +267,22 @@ func validateManifest(img v1.Image) error {
return nil
}
func layersExist(layers []v1.Layer) error {
errs := []string{}
for _, layer := range layers {
ok, err := partial.Exists(layer)
if err != nil {
errs = append(errs, err.Error())
}
if !ok {
errs = append(errs, "layer does not exist")
}
}
if len(errs) != 0 {
return errors.New(strings.Join(errs, "\n"))
}
return nil
}
+26 -6
View File
@@ -27,10 +27,10 @@ import (
)
// Index validates that idx does not violate any invariants of the index format.
func Index(idx v1.ImageIndex) error {
func Index(idx v1.ImageIndex, opt ...Option) error {
errs := []string{}
if err := validateChildren(idx); err != nil {
if err := validateChildren(idx, opt...); err != nil {
errs = append(errs, fmt.Sprintf("validating children: %v", err))
}
@@ -44,7 +44,11 @@ func Index(idx v1.ImageIndex) error {
return nil
}
func validateChildren(idx v1.ImageIndex) error {
type withLayer interface {
Layer(v1.Hash) (v1.Layer, error)
}
func validateChildren(idx v1.ImageIndex, opt ...Option) error {
manifest, err := idx.IndexManifest()
if err != nil {
return err
@@ -58,7 +62,7 @@ func validateChildren(idx v1.ImageIndex) error {
if err != nil {
return err
}
if err := Index(idx); err != nil {
if err := Index(idx, opt...); err != nil {
errs = append(errs, fmt.Sprintf("failed to validate index Manifests[%d](%s): %v", i, desc.Digest, err))
}
if err := validateMediaType(idx, desc.MediaType); err != nil {
@@ -69,14 +73,30 @@ func validateChildren(idx v1.ImageIndex) error {
if err != nil {
return err
}
if err := Image(img); err != nil {
if err := Image(img, opt...); err != nil {
errs = append(errs, fmt.Sprintf("failed to validate image Manifests[%d](%s): %v", i, desc.Digest, err))
}
if err := validateMediaType(img, desc.MediaType); err != nil {
errs = append(errs, fmt.Sprintf("failed to validate image MediaType[%d](%s): %v", i, desc.Digest, err))
}
default:
logs.Warn.Printf("Unexpected manifest: %s", desc.MediaType)
// Workaround for #819.
if wl, ok := idx.(withLayer); ok {
layer, err := wl.Layer(desc.Digest)
if err != nil {
return fmt.Errorf("failed to get layer Manifests[%d]: %w", i, err)
}
if err := Layer(layer, opt...); err != nil {
lerr := fmt.Sprintf("failed to validate layer Manifests[%d](%s): %v", i, desc.Digest, err)
if desc.MediaType.IsDistributable() {
errs = append(errs, lerr)
} else {
logs.Warn.Printf("nondistributable layer failure: %v", lerr)
}
}
} else {
logs.Warn.Printf("Unexpected manifest: %s", desc.MediaType)
}
}
}
+15 -2
View File
@@ -26,11 +26,24 @@ import (
"strings"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/partial"
)
// Layer validates that the values return by its methods are consistent with the
// contents returned by Compressed and Uncompressed.
func Layer(layer v1.Layer) error {
func Layer(layer v1.Layer, opt ...Option) error {
o := makeOptions(opt...)
if o.fast {
ok, err := partial.Exists(layer)
if err != nil {
return err
}
if !ok {
return fmt.Errorf("layer does not exist")
}
return nil
}
cl, err := computeLayer(layer)
if err != nil {
return err
@@ -128,7 +141,7 @@ func computeLayer(layer v1.Layer) (*computedLayer, error) {
files := make(map[string]struct{})
for {
hdr, err := tarReader.Next()
if err == io.EOF {
if errors.Is(err, io.EOF) {
break
}
if err != nil {
@@ -0,0 +1,37 @@
// Copyright 2021 Google LLC All Rights Reserved.
//
// 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 validate
// Option is a functional option for validate.
type Option func(*options)
type options struct {
fast bool
}
func makeOptions(opts ...Option) options {
opt := options{
fast: false,
}
for _, o := range opts {
o(&opt)
}
return opt
}
// Fast causes validate to skip reading and digesting layer bytes.
func Fast(o *options) {
o.fast = true
}