1package storage 2 3import ( 4 "context" 5 "fmt" 6 7 "github.com/docker/distribution" 8 dcontext "github.com/docker/distribution/context" 9 "github.com/docker/distribution/manifest/manifestlist" 10 "github.com/opencontainers/go-digest" 11) 12 13// manifestListHandler is a ManifestHandler that covers schema2 manifest lists. 14type manifestListHandler struct { 15 repository distribution.Repository 16 blobStore distribution.BlobStore 17 ctx context.Context 18} 19 20var _ ManifestHandler = &manifestListHandler{} 21 22func (ms *manifestListHandler) Unmarshal(ctx context.Context, dgst digest.Digest, content []byte) (distribution.Manifest, error) { 23 dcontext.GetLogger(ms.ctx).Debug("(*manifestListHandler).Unmarshal") 24 25 m := &manifestlist.DeserializedManifestList{} 26 if err := m.UnmarshalJSON(content); err != nil { 27 return nil, err 28 } 29 30 return m, nil 31} 32 33func (ms *manifestListHandler) Put(ctx context.Context, manifestList distribution.Manifest, skipDependencyVerification bool) (digest.Digest, error) { 34 dcontext.GetLogger(ms.ctx).Debug("(*manifestListHandler).Put") 35 36 m, ok := manifestList.(*manifestlist.DeserializedManifestList) 37 if !ok { 38 return "", fmt.Errorf("wrong type put to manifestListHandler: %T", manifestList) 39 } 40 41 if err := ms.verifyManifest(ms.ctx, *m, skipDependencyVerification); err != nil { 42 return "", err 43 } 44 45 mt, payload, err := m.Payload() 46 if err != nil { 47 return "", err 48 } 49 50 revision, err := ms.blobStore.Put(ctx, mt, payload) 51 if err != nil { 52 dcontext.GetLogger(ctx).Errorf("error putting payload into blobstore: %v", err) 53 return "", err 54 } 55 56 return revision.Digest, nil 57} 58 59// verifyManifest ensures that the manifest content is valid from the 60// perspective of the registry. As a policy, the registry only tries to 61// store valid content, leaving trust policies of that content up to 62// consumers. 63func (ms *manifestListHandler) verifyManifest(ctx context.Context, mnfst manifestlist.DeserializedManifestList, skipDependencyVerification bool) error { 64 var errs distribution.ErrManifestVerification 65 66 if mnfst.SchemaVersion != 2 { 67 return fmt.Errorf("unrecognized manifest list schema version %d", mnfst.SchemaVersion) 68 } 69 70 if !skipDependencyVerification { 71 // This manifest service is different from the blob service 72 // returned by Blob. It uses a linked blob store to ensure that 73 // only manifests are accessible. 74 75 manifestService, err := ms.repository.Manifests(ctx) 76 if err != nil { 77 return err 78 } 79 80 for _, manifestDescriptor := range mnfst.References() { 81 exists, err := manifestService.Exists(ctx, manifestDescriptor.Digest) 82 if err != nil && err != distribution.ErrBlobUnknown { 83 errs = append(errs, err) 84 } 85 if err != nil || !exists { 86 // On error here, we always append unknown blob errors. 87 errs = append(errs, distribution.ErrManifestBlobUnknown{Digest: manifestDescriptor.Digest}) 88 } 89 } 90 } 91 if len(errs) != 0 { 92 return errs 93 } 94 95 return nil 96} 97