registry/storage/validation/schema2.go (73 lines of code) (raw):

package validation import ( "context" "fmt" "github.com/docker/distribution" "github.com/docker/distribution/manifest/schema1" "github.com/docker/distribution/manifest/schema2" ) // Schema2Validator ensures that a schema2 manifest is valid and optionally // verifies all manifest references. type Schema2Validator struct { baseValidator manifestURLs ManifestURLs } // NewSchema2Validator returns a new Schema2Validator. func NewSchema2Validator(exister ManifestExister, statter distribution.BlobStatter, refLimit, payloadLimit int, manifestURLs ManifestURLs) *Schema2Validator { return &Schema2Validator{ baseValidator: baseValidator{ manifestExister: exister, blobStatter: statter, refLimit: refLimit, payloadLimit: payloadLimit, }, manifestURLs: manifestURLs, } } // Validate ensures that the manifest content is valid from the // perspective of the registry. As a policy, the registry only tries to store // valid content, leaving trust policies of that content up to consumers. func (v *Schema2Validator) Validate(ctx context.Context, mnfst *schema2.DeserializedManifest) error { var errs distribution.ErrManifestVerification if mnfst.Manifest.SchemaVersion != 2 { return fmt.Errorf("unrecognized manifest schema version %d", mnfst.Manifest.SchemaVersion) } if err := v.exceedsPayloadSizeLimit(mnfst); err != nil { errs = append(errs, err) return errs } if err := v.exceedsRefLimit(mnfst); err != nil { errs = append(errs, err) return errs } for _, descriptor := range mnfst.References() { var err error switch descriptor.MediaType { case schema2.MediaTypeForeignLayer: // Clients download this layer from an external URL, so do not check for // its presence. if len(descriptor.URLs) == 0 { err = errMissingURL } for _, u := range descriptor.URLs { if !validURL(u, v.manifestURLs) { err = errInvalidURL break } } case schema2.MediaTypeManifest, schema1.MediaTypeManifest: var exists bool exists, err = v.manifestExister.Exists(ctx, descriptor.Digest) if err != nil || !exists { err = distribution.ErrBlobUnknown // just coerce to unknown. } fallthrough // double check the blob store. default: // forward all else to blob storage if len(descriptor.URLs) == 0 { _, err = v.blobStatter.Stat(ctx, descriptor.Digest) } } if err != nil { if err != distribution.ErrBlobUnknown { errs = append(errs, err) } // On error here, we always append unknown blob errors. errs = append(errs, distribution.ErrManifestBlobUnknown{Digest: descriptor.Digest}) } } if len(errs) != 0 { return errs } return nil }