feat: propagate detailed error msgs to client (OCI dist-spec format) (#1681)

Signed-off-by: Alexei Dodon <adodon@cisco.com>
This commit is contained in:
Alexei Dodon
2023-08-23 20:59:52 +03:00
committed by GitHub
parent 94429a82df
commit 247f6dcd3f
10 changed files with 292 additions and 200 deletions
+9 -7
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"math/rand"
"path"
@@ -27,8 +28,7 @@ import (
const (
manifestWithEmptyLayersErrMsg = "layers: Array must have at least 1 items"
cosignSignatureTagSuffix = "sig"
cosignSignatureTagSuffix = "sig"
)
func GetTagsByIndex(index ispec.Index) []string {
@@ -86,7 +86,7 @@ func ValidateManifest(imgStore storageTypes.ImageStore, repo, reference, mediaTy
if err := ValidateManifestSchema(body); err != nil {
log.Error().Err(err).Msg("OCIv1 image manifest schema validation failed")
return "", zerr.ErrBadManifest
return "", zerr.NewError(zerr.ErrBadManifest).AddDetail("jsonSchemaValidation", err.Error())
}
if err := json.Unmarshal(body, &manifest); err != nil {
@@ -125,7 +125,7 @@ func ValidateManifest(imgStore storageTypes.ImageStore, repo, reference, mediaTy
if err := ValidateImageIndexSchema(body); err != nil {
log.Error().Err(err).Msg("OCIv1 image index manifest schema validation failed")
return "", err
return "", zerr.NewError(zerr.ErrBadManifest).AddDetail("jsonSchemaValidation", err.Error())
}
var indexManifest ispec.Index
@@ -219,8 +219,10 @@ func CheckIfIndexNeedsUpdate(index *ispec.Index, desc *ispec.Descriptor,
log.Error().Err(err).
Str("old mediaType", manifest.MediaType).
Str("new mediaType", desc.MediaType).Msg("cannot change media-type")
reason := fmt.Sprintf("changing manifest media-type from \"%s\" to \"%s\" is disallowed",
manifest.MediaType, desc.MediaType)
return false, "", err
return false, "", zerr.NewError(err).AddDetail("reason", reason)
}
oldDesc := *desc
@@ -780,7 +782,7 @@ func IsNonDistributable(mediaType string) bool {
func ValidateManifestSchema(buf []byte) error {
if err := schema.ValidatorMediaTypeManifest.Validate(bytes.NewBuffer(buf)); err != nil {
if !IsEmptyLayersError(err) {
return zerr.ErrBadManifest
return err
}
}
@@ -789,7 +791,7 @@ func ValidateManifestSchema(buf []byte) error {
func ValidateImageIndexSchema(buf []byte) error {
if err := schema.ValidatorMediaTypeImageIndex.Validate(bytes.NewBuffer(buf)); err != nil {
return zerr.ErrBadManifest
return err
}
return nil
+9 -4
View File
@@ -3,6 +3,7 @@ package storage_test
import (
"bytes"
"encoding/json"
"errors"
"os"
"testing"
@@ -12,7 +13,7 @@ import (
"github.com/rs/zerolog"
. "github.com/smartystreets/goconvey/convey"
"zotregistry.io/zot/errors"
zerr "zotregistry.io/zot/errors"
"zotregistry.io/zot/pkg/extensions/monitoring"
"zotregistry.io/zot/pkg/log"
"zotregistry.io/zot/pkg/storage"
@@ -74,6 +75,10 @@ func TestValidateManifest(t *testing.T) {
_, _, err = imgStore.PutImageManifest("test", "1.0", ispec.MediaTypeImageManifest, body)
So(err, ShouldNotBeNil)
var internalErr *zerr.Error
So(errors.As(err, &internalErr), ShouldBeTrue)
So(internalErr.GetDetails(), ShouldContainKey, "jsonSchemaValidation")
So(internalErr.GetDetails()["jsonSchemaValidation"], ShouldEqual, "[schemaVersion: Must be less than or equal to 2]")
})
Convey("manifest with non-distributable layers", func() {
@@ -169,7 +174,7 @@ func TestGetReferrersErrors(t *testing.T) {
return indexBuf, nil
},
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
return []byte{}, errors.ErrBlobNotFound
return []byte{}, zerr.ErrBlobNotFound
},
}
@@ -188,7 +193,7 @@ func TestGetReferrersErrors(t *testing.T) {
return indexBuf, nil
},
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
return []byte{}, errors.ErrBadBlob
return []byte{}, zerr.ErrBadBlob
},
}
@@ -363,7 +368,7 @@ func TestGetImageIndexErrors(t *testing.T) {
Convey("Trigger GetBlobContent error", t, func(c C) {
imgStore := &mocks.MockedImageStore{
GetBlobContentFn: func(repo string, digest godigest.Digest) ([]byte, error) {
return []byte{}, errors.ErrBlobNotFound
return []byte{}, zerr.ErrBlobNotFound
},
}