Remove signature store from registry. Return a generated signature for manifest
pull. Signed-off-by: Richard Scothern <richard.scothern@docker.com>master
							parent
							
								
									84cb77c871
								
							
						
					
					
						commit
						d3b61b612f
					
				|  | @ -1067,13 +1067,13 @@ func testManifestAPISchema1(t *testing.T, env *testEnv, imageName reference.Name | |||
| 		t.Fatalf("error decoding fetched manifest: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	// check two signatures were roundtripped
 | ||||
| 	// check only 1 signature is returned
 | ||||
| 	signatures, err = fetchedManifestByDigest.Signatures() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(signatures) != 2 { | ||||
| 	if len(signatures) != 1 { | ||||
| 		t.Fatalf("expected 2 signature from manifest, got: %d", len(signatures)) | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -155,6 +155,7 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App { | |||
| 	app.configureRedis(config) | ||||
| 	app.configureLogHook(config) | ||||
| 
 | ||||
| 	options := registrymiddleware.GetRegistryOptions() | ||||
| 	if config.Compatibility.Schema1.TrustKey != "" { | ||||
| 		app.trustKey, err = libtrust.LoadKeyFile(config.Compatibility.Schema1.TrustKey) | ||||
| 		if err != nil { | ||||
|  | @ -169,6 +170,8 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	options = append(options, storage.Schema1SigningKey(app.trustKey)) | ||||
| 
 | ||||
| 	if config.HTTP.Host != "" { | ||||
| 		u, err := url.Parse(config.HTTP.Host) | ||||
| 		if err != nil { | ||||
|  | @ -177,17 +180,10 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App { | |||
| 		app.httpHost = *u | ||||
| 	} | ||||
| 
 | ||||
| 	options := registrymiddleware.GetRegistryOptions() | ||||
| 
 | ||||
| 	if app.isCache { | ||||
| 		options = append(options, storage.DisableDigestResumption) | ||||
| 	} | ||||
| 
 | ||||
| 	if config.Compatibility.Schema1.DisableSignatureStore { | ||||
| 		options = append(options, storage.DisableSchema1Signatures) | ||||
| 		options = append(options, storage.Schema1SigningKey(app.trustKey)) | ||||
| 	} | ||||
| 
 | ||||
| 	// configure deletion
 | ||||
| 	if d, ok := config.Storage["delete"]; ok { | ||||
| 		e, ok := d["enabled"] | ||||
|  |  | |||
|  | @ -60,12 +60,6 @@ func (sm statsManifest) Put(ctx context.Context, manifest distribution.Manifest, | |||
| 	return sm.manifests.Put(ctx, manifest) | ||||
| } | ||||
| 
 | ||||
| /*func (sm statsManifest) Enumerate(ctx context.Context, manifests []distribution.Manifest, last distribution.Manifest) (n int, err error) { | ||||
| 	sm.stats["enumerate"]++ | ||||
| 	return sm.manifests.Enumerate(ctx, manifests, last) | ||||
| } | ||||
| */ | ||||
| 
 | ||||
| type mockChallenger struct { | ||||
| 	sync.Mutex | ||||
| 	count int | ||||
|  | @ -75,7 +69,6 @@ type mockChallenger struct { | |||
| func (m *mockChallenger) tryEstablishChallenges(context.Context) error { | ||||
| 	m.Lock() | ||||
| 	defer m.Unlock() | ||||
| 
 | ||||
| 	m.count++ | ||||
| 	return nil | ||||
| } | ||||
|  | @ -93,9 +86,15 @@ func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestE | |||
| 	if err != nil { | ||||
| 		t.Fatalf("unable to parse reference: %s", err) | ||||
| 	} | ||||
| 	k, err := libtrust.GenerateECP256PrivateKey() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
| 	truthRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider())) | ||||
| 	truthRegistry, err := storage.NewRegistry(ctx, inmemory.New(), | ||||
| 		storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), | ||||
| 		storage.Schema1SigningKey(k)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("error creating registry: %v", err) | ||||
| 	} | ||||
|  | @ -117,7 +116,7 @@ func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestE | |||
| 		t.Fatalf(err.Error()) | ||||
| 	} | ||||
| 
 | ||||
| 	localRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), storage.EnableRedirect, storage.DisableDigestResumption) | ||||
| 	localRegistry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), storage.EnableRedirect, storage.DisableDigestResumption, storage.Schema1SigningKey(k)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("error creating registry: %v", err) | ||||
| 	} | ||||
|  |  | |||
|  | @ -69,7 +69,7 @@ var GCCmd = &cobra.Command{ | |||
| 			os.Exit(1) | ||||
| 		} | ||||
| 
 | ||||
| 		registry, err := storage.NewRegistry(ctx, driver, storage.DisableSchema1Signatures, storage.Schema1SigningKey(k)) | ||||
| 		registry, err := storage.NewRegistry(ctx, driver, storage.Schema1SigningKey(k)) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, "failed to construct registry: %v", err) | ||||
| 			os.Exit(1) | ||||
|  |  | |||
|  | @ -75,7 +75,6 @@ func (bs *blobStore) Put(ctx context.Context, mediaType string, p []byte) (distr | |||
| 	} | ||||
| 
 | ||||
| 	// TODO(stevvooe): Write out mediatype here, as well.
 | ||||
| 
 | ||||
| 	return distribution.Descriptor{ | ||||
| 		Size: int64(len(p)), | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,7 +6,6 @@ import ( | |||
| 	"github.com/docker/distribution" | ||||
| 	"github.com/docker/distribution/context" | ||||
| 	"github.com/docker/distribution/digest" | ||||
| 	"github.com/docker/distribution/manifest/schema1" | ||||
| 	"github.com/docker/distribution/manifest/schema2" | ||||
| 	"github.com/docker/distribution/reference" | ||||
| 	"github.com/docker/distribution/registry/storage/driver" | ||||
|  | @ -71,22 +70,6 @@ func MarkAndSweep(ctx context.Context, storageDriver driver.StorageDriver, regis | |||
| 			} | ||||
| 
 | ||||
| 			switch manifest.(type) { | ||||
| 			case *schema1.SignedManifest: | ||||
| 				signaturesGetter, ok := manifestService.(distribution.SignaturesGetter) | ||||
| 				if !ok { | ||||
| 					return fmt.Errorf("unable to convert ManifestService into SignaturesGetter") | ||||
| 				} | ||||
| 				signatures, err := signaturesGetter.GetSignatures(ctx, dgst) | ||||
| 				if err != nil { | ||||
| 					return fmt.Errorf("failed to get signatures for signed manifest: %v", err) | ||||
| 				} | ||||
| 				for _, signatureDigest := range signatures { | ||||
| 					if dryRun { | ||||
| 						emit("%s: marking signature %s", repoName, signatureDigest) | ||||
| 					} | ||||
| 					markSet[signatureDigest] = struct{}{} | ||||
| 				} | ||||
| 				break | ||||
| 			case *schema2.DeserializedManifest: | ||||
| 				config := manifest.(*schema2.DeserializedManifest).Config | ||||
| 				if dryRun { | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ import ( | |||
| 	"github.com/docker/distribution/registry/storage/driver" | ||||
| 	"github.com/docker/distribution/registry/storage/driver/inmemory" | ||||
| 	"github.com/docker/distribution/testutil" | ||||
| 	"github.com/docker/libtrust" | ||||
| ) | ||||
| 
 | ||||
| type image struct { | ||||
|  | @ -22,7 +23,11 @@ type image struct { | |||
| 
 | ||||
| func createRegistry(t *testing.T, driver driver.StorageDriver) distribution.Namespace { | ||||
| 	ctx := context.Background() | ||||
| 	registry, err := NewRegistry(ctx, driver, EnableDelete) | ||||
| 	k, err := libtrust.GenerateECP256PrivateKey() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	registry, err := NewRegistry(ctx, driver, EnableDelete, Schema1SigningKey(k)) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Failed to construct namespace") | ||||
| 	} | ||||
|  | @ -139,13 +144,13 @@ func TestNoDeletionNoEffect(t *testing.T) { | |||
| 	ctx := context.Background() | ||||
| 	inmemoryDriver := inmemory.New() | ||||
| 
 | ||||
| 	registry := createRegistry(t, inmemoryDriver) | ||||
| 	registry := createRegistry(t, inmemory.New()) | ||||
| 	repo := makeRepository(t, registry, "palailogos") | ||||
| 	manifestService, err := repo.Manifests(ctx) | ||||
| 
 | ||||
| 	image1 := uploadRandomSchema1Image(t, repo) | ||||
| 	image2 := uploadRandomSchema1Image(t, repo) | ||||
| 	image3 := uploadRandomSchema2Image(t, repo) | ||||
| 	uploadRandomSchema2Image(t, repo) | ||||
| 
 | ||||
| 	// construct manifestlist for fun.
 | ||||
| 	blobstatter := registry.BlobStatter() | ||||
|  | @ -160,20 +165,17 @@ func TestNoDeletionNoEffect(t *testing.T) { | |||
| 		t.Fatalf("Failed to add manifest list: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	before := allBlobs(t, registry) | ||||
| 
 | ||||
| 	// Run GC
 | ||||
| 	err = MarkAndSweep(context.Background(), inmemoryDriver, registry, false) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Failed mark and sweep: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	blobs := allBlobs(t, registry) | ||||
| 
 | ||||
| 	// the +1 at the end is for the manifestList
 | ||||
| 	// the first +3 at the end for each manifest's blob
 | ||||
| 	// the second +3 at the end for each manifest's signature/config layer
 | ||||
| 	totalBlobCount := len(image1.layers) + len(image2.layers) + len(image3.layers) + 1 + 3 + 3 | ||||
| 	if len(blobs) != totalBlobCount { | ||||
| 		t.Fatalf("Garbage collection affected storage") | ||||
| 	after := allBlobs(t, registry) | ||||
| 	if len(before) != len(after) { | ||||
| 		t.Fatalf("Garbage collection affected storage: %d != %d", len(before), len(after)) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,7 +2,6 @@ package storage | |||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path" | ||||
| 
 | ||||
| 	"encoding/json" | ||||
| 	"github.com/docker/distribution" | ||||
|  | @ -12,7 +11,6 @@ import ( | |||
| 	"github.com/docker/distribution/manifest/manifestlist" | ||||
| 	"github.com/docker/distribution/manifest/schema1" | ||||
| 	"github.com/docker/distribution/manifest/schema2" | ||||
| 	"github.com/docker/distribution/registry/storage/driver" | ||||
| ) | ||||
| 
 | ||||
| // A ManifestHandler gets and puts manifests of a particular type.
 | ||||
|  | @ -141,48 +139,3 @@ func (ms *manifestStore) Enumerate(ctx context.Context, ingester func(digest.Dig | |||
| 	}) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // Only valid for schema1 signed manifests
 | ||||
| func (ms *manifestStore) GetSignatures(ctx context.Context, manifestDigest digest.Digest) ([]digest.Digest, error) { | ||||
| 	// sanity check that digest refers to a schema1 digest
 | ||||
| 	manifest, err := ms.Get(ctx, manifestDigest) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if _, ok := manifest.(*schema1.SignedManifest); !ok { | ||||
| 		return nil, fmt.Errorf("digest %v is not for schema1 manifest", manifestDigest) | ||||
| 	} | ||||
| 
 | ||||
| 	signaturesPath, err := pathFor(manifestSignaturesPathSpec{ | ||||
| 		name:     ms.repository.Named().Name(), | ||||
| 		revision: manifestDigest, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var digests []digest.Digest | ||||
| 	alg := string(digest.SHA256) | ||||
| 	signaturePaths, err := ms.blobStore.driver.List(ctx, path.Join(signaturesPath, alg)) | ||||
| 
 | ||||
| 	switch err.(type) { | ||||
| 	case nil: | ||||
| 		break | ||||
| 	case driver.PathNotFoundError: | ||||
| 		// Manifest may have been pushed with signature store disabled
 | ||||
| 		return digests, nil | ||||
| 	default: | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, sigPath := range signaturePaths { | ||||
| 		sigdigest, err := digest.ParseDigest(alg + ":" + path.Base(sigPath)) | ||||
| 		if err != nil { | ||||
| 			// merely found not a digest
 | ||||
| 			continue | ||||
| 		} | ||||
| 		digests = append(digests, sigdigest) | ||||
| 	} | ||||
| 	return digests, nil | ||||
| } | ||||
|  |  | |||
|  | @ -52,15 +52,11 @@ func newManifestStoreTestEnv(t *testing.T, name reference.Named, tag string, opt | |||
| } | ||||
| 
 | ||||
| func TestManifestStorage(t *testing.T) { | ||||
| 	testManifestStorage(t, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect) | ||||
| } | ||||
| 
 | ||||
| func TestManifestStorageDisabledSignatures(t *testing.T) { | ||||
| 	k, err := libtrust.GenerateECP256PrivateKey() | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	testManifestStorage(t, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect, DisableSchema1Signatures, Schema1SigningKey(k)) | ||||
| 	testManifestStorage(t, BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), EnableDelete, EnableRedirect, Schema1SigningKey(k)) | ||||
| } | ||||
| 
 | ||||
| func testManifestStorage(t *testing.T, options ...RegistryOption) { | ||||
|  | @ -71,7 +67,6 @@ func testManifestStorage(t *testing.T, options ...RegistryOption) { | |||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	equalSignatures := env.registry.(*registry).schema1SignaturesEnabled | ||||
| 
 | ||||
| 	m := schema1.Manifest{ | ||||
| 		Versioned: manifest.Versioned{ | ||||
|  | @ -175,12 +170,6 @@ func testManifestStorage(t *testing.T, options ...RegistryOption) { | |||
| 		t.Fatalf("fetched payload does not match original payload: %q != %q", fetchedManifest.Canonical, sm.Canonical) | ||||
| 	} | ||||
| 
 | ||||
| 	if equalSignatures { | ||||
| 		if !reflect.DeepEqual(fetchedManifest, sm) { | ||||
| 			t.Fatalf("fetched manifest not equal: %#v != %#v", fetchedManifest.Manifest, sm.Manifest) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	_, pl, err := fetchedManifest.Payload() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("error getting payload %#v", err) | ||||
|  | @ -223,12 +212,6 @@ func testManifestStorage(t *testing.T, options ...RegistryOption) { | |||
| 		t.Fatalf("fetched manifest not equal: %q != %q", byDigestManifest.Canonical, fetchedManifest.Canonical) | ||||
| 	} | ||||
| 
 | ||||
| 	if equalSignatures { | ||||
| 		if !reflect.DeepEqual(fetchedByDigest, fetchedManifest) { | ||||
| 			t.Fatalf("fetched manifest not equal: %#v != %#v", fetchedByDigest, fetchedManifest) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	sigs, err := fetchedJWS.Signatures() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unable to extract signatures: %v", err) | ||||
|  | @ -285,17 +268,6 @@ func testManifestStorage(t *testing.T, options ...RegistryOption) { | |||
| 		t.Fatalf("unexpected error verifying manifest: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	// Assemble our payload and two signatures to get what we expect!
 | ||||
| 	expectedJWS, err := libtrust.NewJSONSignature(payload, sigs[0], sigs2[0]) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unexpected error merging jws: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	expectedSigs, err := expectedJWS.Signatures() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("unexpected error getting expected signatures: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	_, pl, err = fetched.Payload() | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("error getting payload %#v", err) | ||||
|  | @ -315,19 +287,6 @@ func testManifestStorage(t *testing.T, options ...RegistryOption) { | |||
| 		t.Fatalf("payloads are not equal") | ||||
| 	} | ||||
| 
 | ||||
| 	if equalSignatures { | ||||
| 		receivedSigs, err := receivedJWS.Signatures() | ||||
| 		if err != nil { | ||||
| 			t.Fatalf("error getting signatures: %v", err) | ||||
| 		} | ||||
| 
 | ||||
| 		for i, sig := range receivedSigs { | ||||
| 			if !bytes.Equal(sig, expectedSigs[i]) { | ||||
| 				t.Fatalf("mismatched signatures from remote: %v != %v", string(sig), string(expectedSigs[i])) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Test deleting manifests
 | ||||
| 	err = ms.Delete(ctx, dgst) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -30,8 +30,6 @@ const ( | |||
| // 						revisions
 | ||||
| //							-> <manifest digest path>
 | ||||
| //								-> link
 | ||||
| //								-> signatures
 | ||||
| // 									<algorithm>/<digest>/link
 | ||||
| // 						tags/<tag>
 | ||||
| //							-> current/link
 | ||||
| // 							-> index
 | ||||
|  | @ -62,8 +60,7 @@ const ( | |||
| //
 | ||||
| // The third component of the repository directory is the manifests store,
 | ||||
| // which is made up of a revision store and tag store. Manifests are stored in
 | ||||
| // the blob store and linked into the revision store. Signatures are separated
 | ||||
| // from the manifest payload data and linked into the blob store, as well.
 | ||||
| // the blob store and linked into the revision store.
 | ||||
| // While the registry can save all revisions of a manifest, no relationship is
 | ||||
| // implied as to the ordering of changes to a manifest. The tag store provides
 | ||||
| // support for name, tag lookups of manifests, using "current/link" under a
 | ||||
|  | @ -77,8 +74,6 @@ const ( | |||
| // 	manifestRevisionsPathSpec:      <root>/v2/repositories/<name>/_manifests/revisions/
 | ||||
| // 	manifestRevisionPathSpec:      <root>/v2/repositories/<name>/_manifests/revisions/<algorithm>/<hex digest>/
 | ||||
| // 	manifestRevisionLinkPathSpec:  <root>/v2/repositories/<name>/_manifests/revisions/<algorithm>/<hex digest>/link
 | ||||
| // 	manifestSignaturesPathSpec:    <root>/v2/repositories/<name>/_manifests/revisions/<algorithm>/<hex digest>/signatures/
 | ||||
| // 	manifestSignatureLinkPathSpec: <root>/v2/repositories/<name>/_manifests/revisions/<algorithm>/<hex digest>/signatures/<algorithm>/<hex digest>/link
 | ||||
| //
 | ||||
| //	Tags:
 | ||||
| //
 | ||||
|  | @ -148,33 +143,6 @@ func pathFor(spec pathSpec) (string, error) { | |||
| 		} | ||||
| 
 | ||||
| 		return path.Join(root, "link"), nil | ||||
| 	case manifestSignaturesPathSpec: | ||||
| 		root, err := pathFor(manifestRevisionPathSpec{ | ||||
| 			name:     v.name, | ||||
| 			revision: v.revision, | ||||
| 		}) | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 
 | ||||
| 		return path.Join(root, "signatures"), nil | ||||
| 	case manifestSignatureLinkPathSpec: | ||||
| 		root, err := pathFor(manifestSignaturesPathSpec{ | ||||
| 			name:     v.name, | ||||
| 			revision: v.revision, | ||||
| 		}) | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 
 | ||||
| 		signatureComponents, err := digestPathComponents(v.signature, false) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 
 | ||||
| 		return path.Join(root, path.Join(append(signatureComponents, "link")...)), nil | ||||
| 	case manifestTagsPathSpec: | ||||
| 		return path.Join(append(repoPrefix, v.name, "_manifests", "tags")...), nil | ||||
| 	case manifestTagPathSpec: | ||||
|  | @ -325,26 +293,6 @@ type manifestRevisionLinkPathSpec struct { | |||
| 
 | ||||
| func (manifestRevisionLinkPathSpec) pathSpec() {} | ||||
| 
 | ||||
| // manifestSignaturesPathSpec describes the path components for the directory
 | ||||
| // containing all the signatures for the target blob. Entries are named with
 | ||||
| // the underlying key id.
 | ||||
| type manifestSignaturesPathSpec struct { | ||||
| 	name     string | ||||
| 	revision digest.Digest | ||||
| } | ||||
| 
 | ||||
| func (manifestSignaturesPathSpec) pathSpec() {} | ||||
| 
 | ||||
| // manifestSignatureLinkPathSpec describes the path components used to look up
 | ||||
| // a signature file by the hash of its blob.
 | ||||
| type manifestSignatureLinkPathSpec struct { | ||||
| 	name      string | ||||
| 	revision  digest.Digest | ||||
| 	signature digest.Digest | ||||
| } | ||||
| 
 | ||||
| func (manifestSignatureLinkPathSpec) pathSpec() {} | ||||
| 
 | ||||
| // manifestTagsPathSpec describes the path elements required to point to the
 | ||||
| // manifest tags directory.
 | ||||
| type manifestTagsPathSpec struct { | ||||
|  |  | |||
|  | @ -26,21 +26,6 @@ func TestPathMapper(t *testing.T) { | |||
| 			}, | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/link", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: manifestSignatureLinkPathSpec{ | ||||
| 				name:      "foo/bar", | ||||
| 				revision:  "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 				signature: "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/signatures/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/link", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: manifestSignaturesPathSpec{ | ||||
| 				name:     "foo/bar", | ||||
| 				revision: "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", | ||||
| 			}, | ||||
| 			expected: "/docker/registry/v2/repositories/foo/bar/_manifests/revisions/sha256/abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789/signatures", | ||||
| 		}, | ||||
| 		{ | ||||
| 			spec: manifestTagsPathSpec{ | ||||
| 				name: "foo/bar", | ||||
|  | @ -113,7 +98,7 @@ func TestPathMapper(t *testing.T) { | |||
| 	// Add a few test cases to ensure we cover some errors
 | ||||
| 
 | ||||
| 	// Specify a path that requires a revision and get a digest validation error.
 | ||||
| 	badpath, err := pathFor(manifestSignaturesPathSpec{ | ||||
| 	badpath, err := pathFor(manifestRevisionPathSpec{ | ||||
| 		name: "foo/bar", | ||||
| 	}) | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,7 +18,6 @@ type registry struct { | |||
| 	blobDescriptorCacheProvider  cache.BlobDescriptorCacheProvider | ||||
| 	deleteEnabled                bool | ||||
| 	resumableDigestEnabled       bool | ||||
| 	schema1SignaturesEnabled     bool | ||||
| 	schema1SigningKey            libtrust.PrivateKey | ||||
| 	blobDescriptorServiceFactory distribution.BlobDescriptorServiceFactory | ||||
| } | ||||
|  | @ -47,17 +46,8 @@ func DisableDigestResumption(registry *registry) error { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DisableSchema1Signatures is a functional option for NewRegistry. It disables
 | ||||
| // signature storage and ensures all schema1 manifests will only be returned
 | ||||
| // with a signature from a provided signing key.
 | ||||
| func DisableSchema1Signatures(registry *registry) error { | ||||
| 	registry.schema1SignaturesEnabled = false | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Schema1SigningKey returns a functional option for NewRegistry. It sets the
 | ||||
| // signing key for adding a signature to all schema1 manifests. This should be
 | ||||
| // used in conjunction with disabling signature store.
 | ||||
| // key for signing  all schema1 manifests.
 | ||||
| func Schema1SigningKey(key libtrust.PrivateKey) RegistryOption { | ||||
| 	return func(registry *registry) error { | ||||
| 		registry.schema1SigningKey = key | ||||
|  | @ -116,9 +106,8 @@ func NewRegistry(ctx context.Context, driver storagedriver.StorageDriver, option | |||
| 			statter: statter, | ||||
| 			pathFn:  bs.path, | ||||
| 		}, | ||||
| 		statter:                  statter, | ||||
| 		resumableDigestEnabled:   true, | ||||
| 		schema1SignaturesEnabled: true, | ||||
| 		statter:                statter, | ||||
| 		resumableDigestEnabled: true, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, option := range options { | ||||
|  | @ -231,11 +220,6 @@ func (repo *repository) Manifests(ctx context.Context, options ...distribution.M | |||
| 			ctx:        ctx, | ||||
| 			repository: repo, | ||||
| 			blobStore:  blobStore, | ||||
| 			signatures: &signatureStore{ | ||||
| 				ctx:        ctx, | ||||
| 				repository: repo, | ||||
| 				blobStore:  repo.blobStore, | ||||
| 			}, | ||||
| 		}, | ||||
| 		schema2Handler: &schema2ManifestHandler{ | ||||
| 			ctx:        ctx, | ||||
|  |  | |||
|  | @ -1,131 +0,0 @@ | |||
| package storage | ||||
| 
 | ||||
| import ( | ||||
| 	"path" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/docker/distribution/context" | ||||
| 	"github.com/docker/distribution/digest" | ||||
| ) | ||||
| 
 | ||||
| type signatureStore struct { | ||||
| 	repository *repository | ||||
| 	blobStore  *blobStore | ||||
| 	ctx        context.Context | ||||
| } | ||||
| 
 | ||||
| func (s *signatureStore) Get(dgst digest.Digest) ([][]byte, error) { | ||||
| 	signaturesPath, err := pathFor(manifestSignaturesPathSpec{ | ||||
| 		name:     s.repository.Named().Name(), | ||||
| 		revision: dgst, | ||||
| 	}) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Need to append signature digest algorithm to path to get all items.
 | ||||
| 	// Perhaps, this should be in the pathMapper but it feels awkward. This
 | ||||
| 	// can be eliminated by implementing listAll on drivers.
 | ||||
| 	signaturesPath = path.Join(signaturesPath, "sha256") | ||||
| 
 | ||||
| 	signaturePaths, err := s.blobStore.driver.List(s.ctx, signaturesPath) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	var wg sync.WaitGroup | ||||
| 	type result struct { | ||||
| 		index     int | ||||
| 		signature []byte | ||||
| 		err       error | ||||
| 	} | ||||
| 	ch := make(chan result) | ||||
| 
 | ||||
| 	bs := s.linkedBlobStore(s.ctx, dgst) | ||||
| 	for i, sigPath := range signaturePaths { | ||||
| 		sigdgst, err := digest.ParseDigest("sha256:" + path.Base(sigPath)) | ||||
| 		if err != nil { | ||||
| 			context.GetLogger(s.ctx).Errorf("could not get digest from path: %q, skipping", sigPath) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		wg.Add(1) | ||||
| 		go func(idx int, sigdgst digest.Digest) { | ||||
| 			defer wg.Done() | ||||
| 			context.GetLogger(s.ctx). | ||||
| 				Debugf("fetching signature %q", sigdgst) | ||||
| 
 | ||||
| 			r := result{index: idx} | ||||
| 
 | ||||
| 			if p, err := bs.Get(s.ctx, sigdgst); err != nil { | ||||
| 				context.GetLogger(s.ctx). | ||||
| 					Errorf("error fetching signature %q: %v", sigdgst, err) | ||||
| 				r.err = err | ||||
| 			} else { | ||||
| 				r.signature = p | ||||
| 			} | ||||
| 
 | ||||
| 			ch <- r | ||||
| 		}(i, sigdgst) | ||||
| 	} | ||||
| 	done := make(chan struct{}) | ||||
| 	go func() { | ||||
| 		wg.Wait() | ||||
| 		close(done) | ||||
| 	}() | ||||
| 
 | ||||
| 	// aggregrate the results
 | ||||
| 	signatures := make([][]byte, len(signaturePaths)) | ||||
| loop: | ||||
| 	for { | ||||
| 		select { | ||||
| 		case result := <-ch: | ||||
| 			signatures[result.index] = result.signature | ||||
| 			if result.err != nil && err == nil { | ||||
| 				// only set the first one.
 | ||||
| 				err = result.err | ||||
| 			} | ||||
| 		case <-done: | ||||
| 			break loop | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return signatures, err | ||||
| } | ||||
| 
 | ||||
| func (s *signatureStore) Put(dgst digest.Digest, signatures ...[]byte) error { | ||||
| 	bs := s.linkedBlobStore(s.ctx, dgst) | ||||
| 	for _, signature := range signatures { | ||||
| 		if _, err := bs.Put(s.ctx, "application/json", signature); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // linkedBlobStore returns the namedBlobStore of the signatures for the
 | ||||
| // manifest with the given digest. Effectively, each signature link path
 | ||||
| // layout is a unique linked blob store.
 | ||||
| func (s *signatureStore) linkedBlobStore(ctx context.Context, revision digest.Digest) *linkedBlobStore { | ||||
| 	linkpath := func(name string, dgst digest.Digest) (string, error) { | ||||
| 		return pathFor(manifestSignatureLinkPathSpec{ | ||||
| 			name:      name, | ||||
| 			revision:  revision, | ||||
| 			signature: dgst, | ||||
| 		}) | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	return &linkedBlobStore{ | ||||
| 		ctx:        ctx, | ||||
| 		repository: s.repository, | ||||
| 		blobStore:  s.blobStore, | ||||
| 		blobAccessController: &linkedBlobStatter{ | ||||
| 			blobStore:   s.blobStore, | ||||
| 			repository:  s.repository, | ||||
| 			linkPathFns: []linkPathFunc{linkpath}, | ||||
| 		}, | ||||
| 		linkPathFns: []linkPathFunc{linkpath}, | ||||
| 	} | ||||
| } | ||||
|  | @ -18,7 +18,6 @@ type signedManifestHandler struct { | |||
| 	repository *repository | ||||
| 	blobStore  *linkedBlobStore | ||||
| 	ctx        context.Context | ||||
| 	signatures *signatureStore | ||||
| } | ||||
| 
 | ||||
| var _ ManifestHandler = &signedManifestHandler{} | ||||
|  | @ -30,13 +29,6 @@ func (ms *signedManifestHandler) Unmarshal(ctx context.Context, dgst digest.Dige | |||
| 		signatures [][]byte | ||||
| 		err        error | ||||
| 	) | ||||
| 	if ms.repository.schema1SignaturesEnabled { | ||||
| 		// Fetch the signatures for the manifest
 | ||||
| 		signatures, err = ms.signatures.Get(dgst) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	jsig, err := libtrust.NewJSONSignature(content, signatures...) | ||||
| 	if err != nil { | ||||
|  | @ -47,8 +39,6 @@ func (ms *signedManifestHandler) Unmarshal(ctx context.Context, dgst digest.Dige | |||
| 		if err := jsig.Sign(ms.repository.schema1SigningKey); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} else if !ms.repository.schema1SignaturesEnabled { | ||||
| 		return nil, fmt.Errorf("missing signing key with signature store disabled") | ||||
| 	} | ||||
| 
 | ||||
| 	// Extract the pretty JWS
 | ||||
|  | @ -90,18 +80,6 @@ func (ms *signedManifestHandler) Put(ctx context.Context, manifest distribution. | |||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	if ms.repository.schema1SignaturesEnabled { | ||||
| 		// Grab each json signature and store them.
 | ||||
| 		signatures, err := sm.Signatures() | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 
 | ||||
| 		if err := ms.signatures.Put(revision.Digest, signatures...); err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return revision.Digest, nil | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue