From 589c8a879fea758007a36bd0f00d07aa1000d0cb Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 26 Jan 2016 11:51:22 -0800 Subject: [PATCH 1/3] Update notary to 1.10-3 in all Dockerfiles Signed-off-by: Sebastiaan van Stijn --- Dockerfile.aarch64 | 4 ++-- Dockerfile.armhf | 2 +- Dockerfile.ppc64le | 4 ++-- Dockerfile.s390x | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index b0eb704c92..1d7d56fa50 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -110,11 +110,11 @@ RUN set -x \ && rm -rf "$GOPATH" # Install notary server -ENV NOTARY_COMMIT 0c11a970826e62479379ccc75a45184460b9200f +ENV NOTARY_VERSION docker-v1.10-3 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ - && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_COMMIT") \ + && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \ && GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \ go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \ && rm -rf "$GOPATH" diff --git a/Dockerfile.armhf b/Dockerfile.armhf index 1bef8ecbcb..fab175de9d 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -144,7 +144,7 @@ RUN set -x \ && rm -rf "$GOPATH" # Install notary server -ENV NOTARY_VERSION docker-v1.10-2 +ENV NOTARY_VERSION docker-v1.10-3 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ diff --git a/Dockerfile.ppc64le b/Dockerfile.ppc64le index dac1878974..a457ae3f50 100644 --- a/Dockerfile.ppc64le +++ b/Dockerfile.ppc64le @@ -123,11 +123,11 @@ RUN set -x \ # TODO update this when we upgrade to Go 1.5.1+ # Install notary server -#ENV NOTARY_COMMIT 8e8122eb5528f621afcd4e2854c47302f17392f7 +#ENV NOTARY_VERSION docker-v1.10-3 #RUN set -x \ # && export GOPATH="$(mktemp -d)" \ # && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ -# && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_COMMIT") \ +# && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \ # && GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \ # go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \ # && rm -rf "$GOPATH" diff --git a/Dockerfile.s390x b/Dockerfile.s390x index fdee716c9e..eac8e71db4 100644 --- a/Dockerfile.s390x +++ b/Dockerfile.s390x @@ -116,11 +116,11 @@ RUN set -x \ && rm -rf "$GOPATH" # Install notary server -ENV NOTARY_COMMIT 8e8122eb5528f621afcd4e2854c47302f17392f7 +ENV NOTARY_VERSION docker-v1.10-3 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ - && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_COMMIT") \ + && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \ && GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \ go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \ && rm -rf "$GOPATH" From 8fd2c8791d9c7cf0dd28b77565f0a04349a8c9a2 Mon Sep 17 00:00:00 2001 From: cyli Date: Tue, 26 Jan 2016 14:21:07 -0800 Subject: [PATCH 2/3] Re-vendor notary, as well as change jfrazelle/go to docker/go. Signed-off-by: cyli --- Dockerfile | 2 +- Dockerfile.aarch64 | 2 +- Dockerfile.armhf | 2 +- Dockerfile.ppc64le | 2 +- Dockerfile.s390x | 2 +- hack/vendor.sh | 4 +- .../{jfrazelle => docker}/go/LICENSE | 0 .../go/canonical/json/decode.go | 0 .../go/canonical/json/encode.go | 0 .../go/canonical/json/fold.go | 0 .../go/canonical/json/indent.go | 0 .../go/canonical/json/scanner.go | 0 .../go/canonical/json/stream.go | 0 .../go/canonical/json/tags.go | 0 vendor/src/github.com/docker/notary/Makefile | 3 +- .../notary/certs/{certmanager.go => certs.go} | 81 +------- .../src/github.com/docker/notary/circle.yml | 10 +- .../github.com/docker/notary/client/client.go | 175 +++++++++++++++--- .../docker/notary/client/helpers.go | 18 +- vendor/src/github.com/docker/notary/const.go | 8 + .../notary/cryptoservice/crypto_service.go | 2 +- .../docker/notary/trustmanager/x509utils.go | 52 +++++- .../docker/notary/tuf/client/client.go | 30 +-- .../github.com/docker/notary/tuf/data/keys.go | 2 +- .../docker/notary/tuf/data/roles.go | 6 +- .../github.com/docker/notary/tuf/data/root.go | 2 +- .../docker/notary/tuf/data/serializer.go | 2 +- .../docker/notary/tuf/data/snapshot.go | 2 +- .../docker/notary/tuf/data/targets.go | 2 +- .../docker/notary/tuf/data/timestamp.go | 2 +- .../docker/notary/tuf/data/types.go | 2 +- .../github.com/docker/notary/tuf/keys/db.go | 9 + .../docker/notary/tuf/signed/verify.go | 2 +- .../docker/notary/tuf/store/filestore.go | 29 ++- .../docker/notary/tuf/store/httpstore.go | 14 ++ .../docker/notary/tuf/store/interfaces.go | 2 + .../docker/notary/tuf/store/memorystore.go | 15 ++ .../docker/notary/tuf/store/offlinestore.go | 22 ++- .../src/github.com/docker/notary/tuf/tuf.go | 5 + 39 files changed, 353 insertions(+), 158 deletions(-) rename vendor/src/github.com/{jfrazelle => docker}/go/LICENSE (100%) rename vendor/src/github.com/{jfrazelle => docker}/go/canonical/json/decode.go (100%) rename vendor/src/github.com/{jfrazelle => docker}/go/canonical/json/encode.go (100%) rename vendor/src/github.com/{jfrazelle => docker}/go/canonical/json/fold.go (100%) rename vendor/src/github.com/{jfrazelle => docker}/go/canonical/json/indent.go (100%) rename vendor/src/github.com/{jfrazelle => docker}/go/canonical/json/scanner.go (100%) rename vendor/src/github.com/{jfrazelle => docker}/go/canonical/json/stream.go (100%) rename vendor/src/github.com/{jfrazelle => docker}/go/canonical/json/tags.go (100%) rename vendor/src/github.com/docker/notary/certs/{certmanager.go => certs.go} (79%) diff --git a/Dockerfile b/Dockerfile index 71d5017517..f27dabd800 100644 --- a/Dockerfile +++ b/Dockerfile @@ -167,7 +167,7 @@ RUN set -x \ && rm -rf "$GOPATH" # Install notary server -ENV NOTARY_VERSION docker-v1.10-3 +ENV NOTARY_VERSION docker-v1.10-4 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index 1d7d56fa50..af92ea7b31 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -110,7 +110,7 @@ RUN set -x \ && rm -rf "$GOPATH" # Install notary server -ENV NOTARY_VERSION docker-v1.10-3 +ENV NOTARY_VERSION docker-v1.10-4 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ diff --git a/Dockerfile.armhf b/Dockerfile.armhf index fab175de9d..60c4373a10 100644 --- a/Dockerfile.armhf +++ b/Dockerfile.armhf @@ -144,7 +144,7 @@ RUN set -x \ && rm -rf "$GOPATH" # Install notary server -ENV NOTARY_VERSION docker-v1.10-3 +ENV NOTARY_VERSION docker-v1.10-4 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ diff --git a/Dockerfile.ppc64le b/Dockerfile.ppc64le index a457ae3f50..5c72840e10 100644 --- a/Dockerfile.ppc64le +++ b/Dockerfile.ppc64le @@ -123,7 +123,7 @@ RUN set -x \ # TODO update this when we upgrade to Go 1.5.1+ # Install notary server -#ENV NOTARY_VERSION docker-v1.10-3 +#ENV NOTARY_VERSION docker-v1.10-4 #RUN set -x \ # && export GOPATH="$(mktemp -d)" \ # && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ diff --git a/Dockerfile.s390x b/Dockerfile.s390x index eac8e71db4..a8c76dcb07 100644 --- a/Dockerfile.s390x +++ b/Dockerfile.s390x @@ -116,7 +116,7 @@ RUN set -x \ && rm -rf "$GOPATH" # Install notary server -ENV NOTARY_VERSION docker-v1.10-3 +ENV NOTARY_VERSION docker-v1.10-4 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ diff --git a/hack/vendor.sh b/hack/vendor.sh index 5d7fe31c95..41d987a9c1 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -50,11 +50,11 @@ clone git github.com/docker/distribution c301f8ab27f4913c968b8d73a38e5dda79b9d3d clone git github.com/vbatts/tar-split v0.9.11 # get desired notary commit, might also need to be updated in Dockerfile -clone git github.com/docker/notary docker-v1.10-3 +clone git github.com/docker/notary docker-v1.10-4 clone git google.golang.org/grpc 174192fc93efcb188fc8f46ca447f0da606b6885 https://github.com/grpc/grpc-go.git clone git github.com/miekg/pkcs11 80f102b5cac759de406949c47f0928b99bd64cdf -clone git github.com/jfrazelle/go v1.5.1-1 +clone git github.com/docker/go v1.5.1-1-1-gbaf439e clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c clone git github.com/opencontainers/runc f36b00aa12b3cb4e9c42506059fce4145cfbd626 # libcontainer diff --git a/vendor/src/github.com/jfrazelle/go/LICENSE b/vendor/src/github.com/docker/go/LICENSE similarity index 100% rename from vendor/src/github.com/jfrazelle/go/LICENSE rename to vendor/src/github.com/docker/go/LICENSE diff --git a/vendor/src/github.com/jfrazelle/go/canonical/json/decode.go b/vendor/src/github.com/docker/go/canonical/json/decode.go similarity index 100% rename from vendor/src/github.com/jfrazelle/go/canonical/json/decode.go rename to vendor/src/github.com/docker/go/canonical/json/decode.go diff --git a/vendor/src/github.com/jfrazelle/go/canonical/json/encode.go b/vendor/src/github.com/docker/go/canonical/json/encode.go similarity index 100% rename from vendor/src/github.com/jfrazelle/go/canonical/json/encode.go rename to vendor/src/github.com/docker/go/canonical/json/encode.go diff --git a/vendor/src/github.com/jfrazelle/go/canonical/json/fold.go b/vendor/src/github.com/docker/go/canonical/json/fold.go similarity index 100% rename from vendor/src/github.com/jfrazelle/go/canonical/json/fold.go rename to vendor/src/github.com/docker/go/canonical/json/fold.go diff --git a/vendor/src/github.com/jfrazelle/go/canonical/json/indent.go b/vendor/src/github.com/docker/go/canonical/json/indent.go similarity index 100% rename from vendor/src/github.com/jfrazelle/go/canonical/json/indent.go rename to vendor/src/github.com/docker/go/canonical/json/indent.go diff --git a/vendor/src/github.com/jfrazelle/go/canonical/json/scanner.go b/vendor/src/github.com/docker/go/canonical/json/scanner.go similarity index 100% rename from vendor/src/github.com/jfrazelle/go/canonical/json/scanner.go rename to vendor/src/github.com/docker/go/canonical/json/scanner.go diff --git a/vendor/src/github.com/jfrazelle/go/canonical/json/stream.go b/vendor/src/github.com/docker/go/canonical/json/stream.go similarity index 100% rename from vendor/src/github.com/jfrazelle/go/canonical/json/stream.go rename to vendor/src/github.com/docker/go/canonical/json/stream.go diff --git a/vendor/src/github.com/jfrazelle/go/canonical/json/tags.go b/vendor/src/github.com/docker/go/canonical/json/tags.go similarity index 100% rename from vendor/src/github.com/jfrazelle/go/canonical/json/tags.go rename to vendor/src/github.com/docker/go/canonical/json/tags.go diff --git a/vendor/src/github.com/docker/notary/Makefile b/vendor/src/github.com/docker/notary/Makefile index c632423ffa..1f45ed5dd2 100644 --- a/vendor/src/github.com/docker/notary/Makefile +++ b/vendor/src/github.com/docker/notary/Makefile @@ -118,12 +118,13 @@ protos: # be run first define gocover -$(GO_EXC) test $(OPTS) $(TESTOPTS) -covermode="$(COVERMODE)" -coverprofile="$(COVERDIR)/$(subst /,-,$(1)).$(subst $(_space),.,$(NOTARY_BUILDTAGS)).cover" "$(1)" || exit 1; +$(GO_EXC) test $(OPTS) $(TESTOPTS) -covermode="$(COVERMODE)" -coverprofile="$(COVERDIR)/$(subst /,-,$(1)).$(subst $(_space),.,$(NOTARY_BUILDTAGS)).coverage.txt" "$(1)" || exit 1; endef gen-cover: go_version @mkdir -p "$(COVERDIR)" $(foreach PKG,$(PKGS),$(call gocover,$(PKG))) + rm "$(COVERDIR)"/*testutils*.coverage.txt # Generates the cover binaries and runs them all in serial, so this can be used # run all tests with a yubikey without any problems diff --git a/vendor/src/github.com/docker/notary/certs/certmanager.go b/vendor/src/github.com/docker/notary/certs/certs.go similarity index 79% rename from vendor/src/github.com/docker/notary/certs/certmanager.go rename to vendor/src/github.com/docker/notary/certs/certs.go index e73af79ddd..d8ba0d9255 100644 --- a/vendor/src/github.com/docker/notary/certs/certmanager.go +++ b/vendor/src/github.com/docker/notary/certs/certs.go @@ -4,7 +4,6 @@ import ( "crypto/x509" "errors" "fmt" - "path/filepath" "time" "github.com/Sirupsen/logrus" @@ -13,14 +12,6 @@ import ( "github.com/docker/notary/tuf/signed" ) -// Manager is an abstraction around trusted root CA stores -type Manager struct { - trustedCAStore trustmanager.X509Store - trustedCertificateStore trustmanager.X509Store -} - -const trustDir = "trusted_certificates" - // ErrValidationFail is returned when there is no valid trusted certificates // being served inside of the roots.json type ErrValidationFail struct { @@ -45,63 +36,6 @@ func (err ErrRootRotationFail) Error() string { return fmt.Sprintf("could not rotate trust to a new trusted root: %s", err.Reason) } -// NewManager returns an initialized Manager, or an error -// if it fails to load certificates -func NewManager(baseDir string) (*Manager, error) { - trustPath := filepath.Join(baseDir, trustDir) - - // Load all CAs that aren't expired and don't use SHA1 - trustedCAStore, err := trustmanager.NewX509FilteredFileStore(trustPath, func(cert *x509.Certificate) bool { - return cert.IsCA && cert.BasicConstraintsValid && cert.SubjectKeyId != nil && - time.Now().Before(cert.NotAfter) && - cert.SignatureAlgorithm != x509.SHA1WithRSA && - cert.SignatureAlgorithm != x509.DSAWithSHA1 && - cert.SignatureAlgorithm != x509.ECDSAWithSHA1 - }) - if err != nil { - return nil, err - } - - // Load all individual (non-CA) certificates that aren't expired and don't use SHA1 - trustedCertificateStore, err := trustmanager.NewX509FilteredFileStore(trustPath, func(cert *x509.Certificate) bool { - return !cert.IsCA && - time.Now().Before(cert.NotAfter) && - cert.SignatureAlgorithm != x509.SHA1WithRSA && - cert.SignatureAlgorithm != x509.DSAWithSHA1 && - cert.SignatureAlgorithm != x509.ECDSAWithSHA1 - }) - if err != nil { - return nil, err - } - - return &Manager{ - trustedCAStore: trustedCAStore, - trustedCertificateStore: trustedCertificateStore, - }, nil -} - -// TrustedCertificateStore returns the trusted certificate store being managed -// by this Manager -func (m *Manager) TrustedCertificateStore() trustmanager.X509Store { - return m.trustedCertificateStore -} - -// TrustedCAStore returns the CA store being managed by this Manager -func (m *Manager) TrustedCAStore() trustmanager.X509Store { - return m.trustedCAStore -} - -// AddTrustedCert adds a cert to the trusted certificate store (not the CA -// store) -func (m *Manager) AddTrustedCert(cert *x509.Certificate) { - m.trustedCertificateStore.AddCert(cert) -} - -// AddTrustedCACert adds a cert to the trusted CA certificate store -func (m *Manager) AddTrustedCACert(cert *x509.Certificate) { - m.trustedCAStore.AddCert(cert) -} - /* ValidateRoot receives a new root, validates its correctness and attempts to do root key rotation if needed. @@ -111,7 +45,7 @@ that list is non-empty means that we've already seen this repository before, and have a list of trusted certificates for it. In this case, we use this list of certificates to attempt to validate this root file. -If the previous validation suceeds, or in the case where we found no trusted +If the previous validation succeeds, or in the case where we found no trusted certificates for this particular GUN, we check the integrity of the root by making sure that it is validated by itself. This means that we will attempt to validate the root data with the certificates that are included in the root keys @@ -129,7 +63,7 @@ we are using the current public PKI to validate the first download of the certif adding an extra layer of security over the normal (SSH style) trust model. We shall call this: TOFUS. */ -func (m *Manager) ValidateRoot(root *data.Signed, gun string) error { +func ValidateRoot(certStore trustmanager.X509Store, root *data.Signed, gun string) error { logrus.Debugf("entered ValidateRoot with dns: %s", gun) signedRoot, err := data.RootFromSigned(root) if err != nil { @@ -144,7 +78,7 @@ func (m *Manager) ValidateRoot(root *data.Signed, gun string) error { } // Retrieve all the trusted certificates that match this gun - certsForCN, err := m.trustedCertificateStore.GetCertificatesByCN(gun) + certsForCN, err := certStore.GetCertificatesByCN(gun) if err != nil { // If the error that we get back is different than ErrNoCertificatesFound // we couldn't check if there are any certificates with this CN already @@ -183,7 +117,7 @@ func (m *Manager) ValidateRoot(root *data.Signed, gun string) error { // Do root certificate rotation: we trust only the certs present in the new root // First we add all the new certificates (even if they already exist) for _, cert := range allValidCerts { - err := m.trustedCertificateStore.AddCert(cert) + err := certStore.AddCert(cert) if err != nil { // If the error is already exists we don't fail the rotation if _, ok := err.(*trustmanager.ErrCertExists); ok { @@ -197,7 +131,7 @@ func (m *Manager) ValidateRoot(root *data.Signed, gun string) error { // Now we delete old certificates that aren't present in the new root for certID, cert := range certsToRemove(certsForCN, allValidCerts) { logrus.Debugf("removing certificate with certID: %s", certID) - err = m.trustedCertificateStore.RemoveCert(cert) + err = certStore.RemoveCert(cert) if err != nil { logrus.Debugf("failed to remove trusted certificate with keyID: %s, %v", certID, err) return &ErrRootRotationFail{Reason: "failed to rotate root keys"} @@ -208,7 +142,7 @@ func (m *Manager) ValidateRoot(root *data.Signed, gun string) error { return nil } -// validRootLeafCerts returns a list of non-exipired, non-sha1 certificates whoose +// validRootLeafCerts returns a list of non-exipired, non-sha1 certificates whose // Common-Names match the provided GUN func validRootLeafCerts(root *data.SignedRoot, gun string) ([]*x509.Certificate, error) { // Get a list of all of the leaf certificates present in root @@ -219,7 +153,8 @@ func validRootLeafCerts(root *data.SignedRoot, gun string) ([]*x509.Certificate, for _, cert := range allLeafCerts { // Validate that this leaf certificate has a CN that matches the exact gun if cert.Subject.CommonName != gun { - logrus.Debugf("error leaf certificate CN: %s doesn't match the given GUN: %s", cert.Subject.CommonName) + logrus.Debugf("error leaf certificate CN: %s doesn't match the given GUN: %s", + cert.Subject.CommonName, gun) continue } // Make sure the certificate is not expired diff --git a/vendor/src/github.com/docker/notary/circle.yml b/vendor/src/github.com/docker/notary/circle.yml index 10a28305d3..99a3639056 100644 --- a/vendor/src/github.com/docker/notary/circle.yml +++ b/vendor/src/github.com/docker/notary/circle.yml @@ -18,6 +18,8 @@ machine: CIRCLE_PAIN: "mode: set" # Put the coverage profile somewhere codecov's script can find it COVERPROFILE: coverage.out + # Set the pull request number so codecov can figure it out + PULL_REQUEST: ${CI_PULL_REQUEST##*/} hosts: # Not used yet @@ -40,8 +42,7 @@ dependencies: # For the stable go version, additionally install linting tools - > gvm use stable && - go get github.com/golang/lint/golint github.com/wadey/gocovmerge && - go install github.com/wadey/gocovmerge + go get github.com/golang/lint/golint test: pre: # Output the go versions we are going to test @@ -72,11 +73,6 @@ test: pwd: $BASE_STABLE post: - - gvm use stable && make covmerge: - timeout: 600 - parallel: true - pwd: $BASE_STABLE - # Report to codecov.io - bash <(curl -s https://codecov.io/bash): parallel: true diff --git a/vendor/src/github.com/docker/notary/client/client.go b/vendor/src/github.com/docker/notary/client/client.go index a3c7b7fe29..b383c94dca 100644 --- a/vendor/src/github.com/docker/notary/client/client.go +++ b/vendor/src/github.com/docker/notary/client/client.go @@ -9,10 +9,10 @@ import ( "net/url" "os" "path/filepath" - "strings" "time" "github.com/Sirupsen/logrus" + "github.com/docker/notary" "github.com/docker/notary/certs" "github.com/docker/notary/client/changelist" "github.com/docker/notary/cryptoservice" @@ -53,9 +53,9 @@ type ErrInvalidRemoteRole struct { Role string } -func (e ErrInvalidRemoteRole) Error() string { +func (err ErrInvalidRemoteRole) Error() string { return fmt.Sprintf( - "notary does not support the server managing the %s key", e.Role) + "notary does not support the server managing the %s key", err.Role) } // ErrRepositoryNotExist is returned when an action is taken on a remote @@ -84,7 +84,7 @@ type NotaryRepository struct { CryptoService signed.CryptoService tufRepo *tuf.Repo roundTrip http.RoundTripper - CertManager *certs.Manager + CertStore trustmanager.X509Store } // repositoryFromKeystores is a helper function for NewNotaryRepository that @@ -93,7 +93,11 @@ type NotaryRepository struct { func repositoryFromKeystores(baseDir, gun, baseURL string, rt http.RoundTripper, keyStores []trustmanager.KeyStore) (*NotaryRepository, error) { - certManager, err := certs.NewManager(baseDir) + certPath := filepath.Join(baseDir, notary.TrustedCertsDir) + certStore, err := trustmanager.NewX509FilteredFileStore( + certPath, + trustmanager.FilterCertsExpiredSha1, + ) if err != nil { return nil, err } @@ -107,7 +111,7 @@ func repositoryFromKeystores(baseDir, gun, baseURL string, rt http.RoundTripper, tufRepoPath: filepath.Join(baseDir, tufDir, filepath.FromSlash(gun)), CryptoService: cryptoService, roundTrip: rt, - CertManager: certManager, + CertStore: certStore, } fileStore, err := store.NewFilesystemStore( @@ -165,7 +169,7 @@ func (r *NotaryRepository) Initialize(rootKeyID string, serverManagedRoles ...st // currently we only support server managing timestamps and snapshots, and // nothing else - timestamps are always managed by the server, and implicit // (do not have to be passed in as part of `serverManagedRoles`, so that - // the API of Initialize doens't change). + // the API of Initialize doesn't change). var serverManagesSnapshot bool locallyManagedKeys := []string{ data.CanonicalTargetsRole, @@ -197,7 +201,7 @@ func (r *NotaryRepository) Initialize(rootKeyID string, serverManagedRoles ...st if err != nil { return err } - r.CertManager.AddTrustedCert(rootCert) + r.CertStore.AddCert(rootCert) // The root key gets stored in the TUF metadata X509 encoded, linking // the tuf root.json to our X509 PKI. @@ -275,8 +279,6 @@ func addChange(cl *changelist.FileChangelist, c changelist.Change, roles ...stri var changes []changelist.Change for _, role := range roles { - role = strings.ToLower(role) - // Ensure we can only add targets to the CanonicalTargetsRole, // or a Delegation role (which is /something else) if role != data.CanonicalTargetsRole && !data.IsDelegation(role) { @@ -347,7 +349,7 @@ func (r *NotaryRepository) AddDelegation(name string, threshold int, // the repository when the changelist gets applied at publish time. // This does not validate that the delegation exists, since one might exist // after applying all changes. -func (r *NotaryRepository) RemoveDelegation(name string) error { +func (r *NotaryRepository) RemoveDelegation(name string, keyIDs, paths []string, removeAll bool) error { if !data.IsDelegation(name) { return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"} @@ -360,20 +362,41 @@ func (r *NotaryRepository) RemoveDelegation(name string) error { defer cl.Close() logrus.Debugf(`Removing delegation "%s"\n`, name) + var template *changelist.TufChange - template := changelist.NewTufChange( - changelist.ActionDelete, - name, - changelist.TypeTargetsDelegation, - "", // no path - nil, - ) + // We use the Delete action only for force removal, Update is used for removing individual keys and paths + if removeAll { + template = changelist.NewTufChange( + changelist.ActionDelete, + name, + changelist.TypeTargetsDelegation, + "", // no path + nil, // deleting role, no data needed + ) + + } else { + tdJSON, err := json.Marshal(&changelist.TufDelegation{ + RemoveKeys: keyIDs, + RemovePaths: paths, + }) + if err != nil { + return err + } + + template = changelist.NewTufChange( + changelist.ActionUpdate, + name, + changelist.TypeTargetsDelegation, + "", // no path + tdJSON, + ) + } return addChange(cl, template, name) } // AddTarget creates new changelist entries to add a target to the given roles -// in the repository when the changelist gets appied at publish time. +// in the repository when the changelist gets applied at publish time. // If roles are unspecified, the default role is "targets". func (r *NotaryRepository) AddTarget(target *Target, roles ...string) error { @@ -431,7 +454,7 @@ func (r *NotaryRepository) ListTargets(roles ...string) ([]*TargetWithRole, erro for _, role := range roles { // we don't need to do anything special with removing role from // roles because listSubtree always processes role and only excludes - // descendent delegations that appear in roles. + // descendant delegations that appear in roles. r.listSubtree(targets, role, roles...) } @@ -509,6 +532,92 @@ func (r *NotaryRepository) GetChangelist() (changelist.Changelist, error) { return cl, nil } +// GetDelegationRoles returns the keys and roles of the repository's delegations +func (r *NotaryRepository) GetDelegationRoles() ([]*data.Role, error) { + // Update state of the repo to latest + if _, err := r.Update(false); err != nil { + return nil, err + } + + // All top level delegations (ex: targets/level1) are stored exclusively in targets.json + targets, ok := r.tufRepo.Targets[data.CanonicalTargetsRole] + if !ok { + return nil, store.ErrMetaNotFound{Resource: data.CanonicalTargetsRole} + } + + allDelegations := targets.Signed.Delegations.Roles + + // make a copy for traversing nested delegations + delegationsList := make([]*data.Role, len(allDelegations)) + copy(delegationsList, allDelegations) + + // Now traverse to lower level delegations (ex: targets/level1/level2) + for len(delegationsList) > 0 { + // Pop off first delegation to traverse + delegation := delegationsList[0] + delegationsList = delegationsList[1:] + + // Get metadata + delegationMeta, ok := r.tufRepo.Targets[delegation.Name] + // If we get an error, don't try to traverse further into this subtree because it doesn't exist or is malformed + if !ok { + continue + } + + // Add nested delegations to return list and exploration list + allDelegations = append(allDelegations, delegationMeta.Signed.Delegations.Roles...) + delegationsList = append(delegationsList, delegationMeta.Signed.Delegations.Roles...) + } + return allDelegations, nil +} + +// RoleWithSignatures is a Role with its associated signatures +type RoleWithSignatures struct { + Signatures []data.Signature + data.Role +} + +// ListRoles returns a list of RoleWithSignatures objects for this repo +// This represents the latest metadata for each role in this repo +func (r *NotaryRepository) ListRoles() ([]RoleWithSignatures, error) { + // Update to latest repo state + _, err := r.Update(false) + if err != nil { + return nil, err + } + + // Get all role info from our updated keysDB, can be empty + roles := r.tufRepo.GetAllLoadedRoles() + + var roleWithSigs []RoleWithSignatures + + // Populate RoleWithSignatures with Role from keysDB and signatures from TUF metadata + for _, role := range roles { + roleWithSig := RoleWithSignatures{Role: *role, Signatures: nil} + switch role.Name { + case data.CanonicalRootRole: + roleWithSig.Signatures = r.tufRepo.Root.Signatures + case data.CanonicalTargetsRole: + roleWithSig.Signatures = r.tufRepo.Targets[data.CanonicalTargetsRole].Signatures + case data.CanonicalSnapshotRole: + roleWithSig.Signatures = r.tufRepo.Snapshot.Signatures + case data.CanonicalTimestampRole: + roleWithSig.Signatures = r.tufRepo.Timestamp.Signatures + default: + // If the role isn't a delegation, we should error -- this is only possible if we have invalid keyDB state + if !data.IsDelegation(role.Name) { + return nil, data.ErrInvalidRole{Role: role.Name, Reason: "invalid role name"} + } + if _, ok := r.tufRepo.Targets[role.Name]; ok { + // We'll only find a signature if we've published any targets with this delegation + roleWithSig.Signatures = r.tufRepo.Targets[role.Name].Signatures + } + } + roleWithSigs = append(roleWithSigs, roleWithSig) + } + return roleWithSigs, nil +} + // Publish pushes the local changes in signed material to the remote notary-server // Conceptually it performs an operation similar to a `git rebase` func (r *NotaryRepository) Publish() error { @@ -837,7 +946,7 @@ func (r *NotaryRepository) validateRoot(rootJSON []byte) (*data.SignedRoot, erro return nil, err } - err = r.CertManager.ValidateRoot(root, r.gun) + err = certs.ValidateRoot(r.CertStore, root, r.gun) if err != nil { return nil, err } @@ -904,3 +1013,27 @@ func (r *NotaryRepository) rootFileKeyChange(role, action string, key data.Publi } return nil } + +// DeleteTrustData removes the trust data stored for this repo in the TUF cache and certificate store on the client side +func (r *NotaryRepository) DeleteTrustData() error { + // Clear TUF files and cache + if err := r.fileStore.RemoveAll(); err != nil { + return fmt.Errorf("error clearing TUF repo data: %v", err) + } + r.tufRepo = tuf.NewRepo(nil, nil) + // Clear certificates + certificates, err := r.CertStore.GetCertificatesByCN(r.gun) + if err != nil { + // If there were no certificates to delete, we're done + if _, ok := err.(*trustmanager.ErrNoCertificatesFound); ok { + return nil + } + return fmt.Errorf("error retrieving certificates for %s: %v", r.gun, err) + } + for _, cert := range certificates { + if err := r.CertStore.RemoveCert(cert); err != nil { + return fmt.Errorf("error removing certificate: %v: %v", cert, err) + } + } + return nil +} diff --git a/vendor/src/github.com/docker/notary/client/helpers.go b/vendor/src/github.com/docker/notary/client/helpers.go index 304ac3d621..a9fd590a9f 100644 --- a/vendor/src/github.com/docker/notary/client/helpers.go +++ b/vendor/src/github.com/docker/notary/client/helpers.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" "path" + "strings" "time" "github.com/Sirupsen/logrus" @@ -85,13 +86,13 @@ func changeTargetsDelegation(repo *tuf.Repo, c changelist.Change) error { return err } if err == nil { - // role existed - return data.ErrInvalidRole{ - Role: c.Scope(), - Reason: "cannot create a role that already exists", + // role existed, attempt to merge paths and keys + if err := r.AddPaths(td.AddPaths); err != nil { + return err } + return repo.UpdateDelegations(r, td.AddKeys) } - // role doesn't exist, create brand new + // create brand new role r, err = td.ToNewRole(c.Scope()) if err != nil { return err @@ -107,7 +108,12 @@ func changeTargetsDelegation(repo *tuf.Repo, c changelist.Change) error { if err != nil { return err } - // role exists, merge + // If we specify the only keys left delete the role, else just delete specified keys + if strings.Join(r.KeyIDs, ";") == strings.Join(td.RemoveKeys, ";") && len(td.AddKeys) == 0 { + r := data.Role{Name: c.Scope()} + return repo.DeleteDelegation(r) + } + // if we aren't deleting and the role exists, merge if err := r.AddPaths(td.AddPaths); err != nil { return err } diff --git a/vendor/src/github.com/docker/notary/const.go b/vendor/src/github.com/docker/notary/const.go index 3c22c05024..6eb278cf98 100644 --- a/vendor/src/github.com/docker/notary/const.go +++ b/vendor/src/github.com/docker/notary/const.go @@ -2,6 +2,14 @@ package notary // application wide constants const ( + // MinThreshold requires a minimum of one threshold for roles; currently we do not support a higher threshold + MinThreshold = 1 + // PrivKeyPerms are the file permissions to use when writing private keys to disk PrivKeyPerms = 0700 + // PubCertPerms are the file permissions to use when writing public certificates to disk PubCertPerms = 0755 + // Sha256HexSize is how big a Sha256 hex is in number of characters + Sha256HexSize = 64 + // TrustedCertsDir is the directory, under the notary repo base directory, where trusted certs are stored + TrustedCertsDir = "trusted_certificates" ) diff --git a/vendor/src/github.com/docker/notary/cryptoservice/crypto_service.go b/vendor/src/github.com/docker/notary/cryptoservice/crypto_service.go index f5bfa073b0..5488c8feff 100644 --- a/vendor/src/github.com/docker/notary/cryptoservice/crypto_service.go +++ b/vendor/src/github.com/docker/notary/cryptoservice/crypto_service.go @@ -69,8 +69,8 @@ func (cs *CryptoService) Create(role, algorithm string) (data.PublicKey, error) if err != nil { return nil, fmt.Errorf("failed to add key to filestore: %v", err) } - return nil, fmt.Errorf("keystores would not accept new private keys for unknown reasons") + return nil, fmt.Errorf("keystores would not accept new private keys for unknown reasons") } // GetPrivateKey returns a private key and role if present by ID. diff --git a/vendor/src/github.com/docker/notary/trustmanager/x509utils.go b/vendor/src/github.com/docker/notary/trustmanager/x509utils.go index 6b0bc76258..64ca1e7226 100644 --- a/vendor/src/github.com/docker/notary/trustmanager/x509utils.go +++ b/vendor/src/github.com/docker/notary/trustmanager/x509utils.go @@ -205,7 +205,8 @@ func GetLeafCerts(certs []*x509.Certificate) []*x509.Certificate { // GetIntermediateCerts parses a list of x509 Certificates and returns all of the // ones marked as a CA, to be used as intermediates -func GetIntermediateCerts(certs []*x509.Certificate) (intCerts []*x509.Certificate) { +func GetIntermediateCerts(certs []*x509.Certificate) []*x509.Certificate { + var intCerts []*x509.Certificate for _, cert := range certs { if cert.IsCA { intCerts = append(intCerts, cert) @@ -299,6 +300,44 @@ func ParsePEMPrivateKey(pemBytes []byte, passphrase string) (data.PrivateKey, er } } +// ParsePEMPublicKey returns a data.PublicKey from a PEM encoded public key or certificate. +func ParsePEMPublicKey(pubKeyBytes []byte) (data.PublicKey, error) { + pemBlock, _ := pem.Decode(pubKeyBytes) + if pemBlock == nil { + return nil, errors.New("no valid public key found") + } + + switch pemBlock.Type { + case "CERTIFICATE": + cert, err := x509.ParseCertificate(pemBlock.Bytes) + if err != nil { + return nil, fmt.Errorf("could not parse provided certificate: %v", err) + } + err = ValidateCertificate(cert) + if err != nil { + return nil, fmt.Errorf("invalid certificate: %v", err) + } + return CertToKey(cert), nil + default: + return nil, fmt.Errorf("unsupported PEM block type %q, expected certificate", pemBlock.Type) + } +} + +// ValidateCertificate returns an error if the certificate is not valid for notary +// Currently, this is only a time expiry check +func ValidateCertificate(c *x509.Certificate) error { + if (c.NotBefore).After(c.NotAfter) { + return fmt.Errorf("certificate validity window is invalid") + } + now := time.Now() + tomorrow := now.AddDate(0, 0, 1) + // Give one day leeway on creation "before" time, check "after" against today + if (tomorrow).Before(c.NotBefore) || now.After(c.NotAfter) { + return fmt.Errorf("certificate is expired") + } + return nil +} + // GenerateRSAKey generates an RSA private key and returns a TUF PrivateKey func GenerateRSAKey(random io.Reader, bits int) (data.PrivateKey, error) { rsaPrivKey, err := rsa.GenerateKey(random, bits) @@ -532,3 +571,14 @@ func X509PublicKeyID(certPubKey data.PublicKey) (string, error) { return key.ID(), nil } + +// FilterCertsExpiredSha1 can be used as the filter function to cert store +// initializers to filter out all expired or SHA-1 certificate that we +// shouldn't load. +func FilterCertsExpiredSha1(cert *x509.Certificate) bool { + return !cert.IsCA && + time.Now().Before(cert.NotAfter) && + cert.SignatureAlgorithm != x509.SHA1WithRSA && + cert.SignatureAlgorithm != x509.DSAWithSHA1 && + cert.SignatureAlgorithm != x509.ECDSAWithSHA1 +} diff --git a/vendor/src/github.com/docker/notary/tuf/client/client.go b/vendor/src/github.com/docker/notary/tuf/client/client.go index 263ee428b1..33ffa20936 100644 --- a/vendor/src/github.com/docker/notary/tuf/client/client.go +++ b/vendor/src/github.com/docker/notary/tuf/client/client.go @@ -54,7 +54,7 @@ func (c *Client) Update() error { if err != nil { logrus.Debug("Error occurred. Root will be downloaded and another update attempted") if err := c.downloadRoot(); err != nil { - logrus.Error("client Update (Root):", err) + logrus.Error("Client Update (Root):", err) return err } // If we error again, we now have the latest root and just want to fail @@ -247,28 +247,27 @@ func (c *Client) downloadTimestamp() error { // We may not have a cached timestamp if this is the first time // we're interacting with the repo. This will result in the // version being 0 - var download bool - old := &data.Signed{} - version := 0 + var ( + saveToCache bool + old *data.Signed + version = 0 + ) cachedTS, err := c.cache.GetMeta(role, maxSize) if err == nil { - err := json.Unmarshal(cachedTS, old) + cached := &data.Signed{} + err := json.Unmarshal(cachedTS, cached) if err == nil { - ts, err := data.TimestampFromSigned(old) + ts, err := data.TimestampFromSigned(cached) if err == nil { version = ts.Signed.Version } - } else { - old = nil + old = cached } } // unlike root, targets and snapshot, always try and download timestamps // from remote, only using the cache one if we couldn't reach remote. raw, s, err := c.downloadSigned(role, maxSize, nil) if err != nil || len(raw) == 0 { - if err, ok := err.(store.ErrMetaNotFound); ok { - return err - } if old == nil { if err == nil { // couldn't retrieve data from server and don't have valid @@ -277,17 +276,18 @@ func (c *Client) downloadTimestamp() error { } return err } - logrus.Debug("using cached timestamp") + logrus.Debug(err.Error()) + logrus.Warn("Error while downloading remote metadata, using cached timestamp - this might not be the latest version available remotely") s = old } else { - download = true + saveToCache = true } err = signed.Verify(s, role, version, c.keysDB) if err != nil { return err } logrus.Debug("successfully verified timestamp") - if download { + if saveToCache { c.cache.SetMeta(role, raw) } ts, err := data.TimestampFromSigned(s) @@ -327,7 +327,7 @@ func (c *Client) downloadSnapshot() error { } err := json.Unmarshal(raw, old) if err == nil { - snap, err := data.TimestampFromSigned(old) + snap, err := data.SnapshotFromSigned(old) if err == nil { version = snap.Signed.Version } else { diff --git a/vendor/src/github.com/docker/notary/tuf/data/keys.go b/vendor/src/github.com/docker/notary/tuf/data/keys.go index 1c2c60e92a..9f94d5552f 100644 --- a/vendor/src/github.com/docker/notary/tuf/data/keys.go +++ b/vendor/src/github.com/docker/notary/tuf/data/keys.go @@ -14,7 +14,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/agl/ed25519" - "github.com/jfrazelle/go/canonical/json" + "github.com/docker/go/canonical/json" ) // PublicKey is the necessary interface for public keys diff --git a/vendor/src/github.com/docker/notary/tuf/data/roles.go b/vendor/src/github.com/docker/notary/tuf/data/roles.go index 25e9ba4572..a505c92304 100644 --- a/vendor/src/github.com/docker/notary/tuf/data/roles.go +++ b/vendor/src/github.com/docker/notary/tuf/data/roles.go @@ -2,6 +2,7 @@ package data import ( "fmt" + "github.com/Sirupsen/logrus" "path" "regexp" "strings" @@ -109,10 +110,7 @@ func NewRole(name string, threshold int, keyIDs, paths, pathHashPrefixes []strin } if IsDelegation(name) { if len(paths) == 0 && len(pathHashPrefixes) == 0 { - return nil, ErrInvalidRole{ - Role: name, - Reason: "roles with no Paths and no PathHashPrefixes will never be able to publish content", - } + logrus.Debugf("role %s with no Paths and no PathHashPrefixes will never be able to publish content until one or more are added", name) } } if threshold < 1 { diff --git a/vendor/src/github.com/docker/notary/tuf/data/root.go b/vendor/src/github.com/docker/notary/tuf/data/root.go index e555cbd2f5..bd479206fd 100644 --- a/vendor/src/github.com/docker/notary/tuf/data/root.go +++ b/vendor/src/github.com/docker/notary/tuf/data/root.go @@ -3,7 +3,7 @@ package data import ( "time" - "github.com/jfrazelle/go/canonical/json" + "github.com/docker/go/canonical/json" ) // SignedRoot is a fully unpacked root.json diff --git a/vendor/src/github.com/docker/notary/tuf/data/serializer.go b/vendor/src/github.com/docker/notary/tuf/data/serializer.go index 91fa1bc93e..5c33d129b4 100644 --- a/vendor/src/github.com/docker/notary/tuf/data/serializer.go +++ b/vendor/src/github.com/docker/notary/tuf/data/serializer.go @@ -1,6 +1,6 @@ package data -import "github.com/jfrazelle/go/canonical/json" +import "github.com/docker/go/canonical/json" // Serializer is an interface that can marshal and unmarshal TUF data. This // is expected to be a canonical JSON marshaller diff --git a/vendor/src/github.com/docker/notary/tuf/data/snapshot.go b/vendor/src/github.com/docker/notary/tuf/data/snapshot.go index ca23d20ff9..f13951ca83 100644 --- a/vendor/src/github.com/docker/notary/tuf/data/snapshot.go +++ b/vendor/src/github.com/docker/notary/tuf/data/snapshot.go @@ -5,7 +5,7 @@ import ( "time" "github.com/Sirupsen/logrus" - "github.com/jfrazelle/go/canonical/json" + "github.com/docker/go/canonical/json" ) // SignedSnapshot is a fully unpacked snapshot.json diff --git a/vendor/src/github.com/docker/notary/tuf/data/targets.go b/vendor/src/github.com/docker/notary/tuf/data/targets.go index 61265ca054..a538d6afa5 100644 --- a/vendor/src/github.com/docker/notary/tuf/data/targets.go +++ b/vendor/src/github.com/docker/notary/tuf/data/targets.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "errors" - "github.com/jfrazelle/go/canonical/json" + "github.com/docker/go/canonical/json" ) // SignedTargets is a fully unpacked targets.json, or target delegation diff --git a/vendor/src/github.com/docker/notary/tuf/data/timestamp.go b/vendor/src/github.com/docker/notary/tuf/data/timestamp.go index da5367ab47..f68252ca5b 100644 --- a/vendor/src/github.com/docker/notary/tuf/data/timestamp.go +++ b/vendor/src/github.com/docker/notary/tuf/data/timestamp.go @@ -4,7 +4,7 @@ import ( "bytes" "time" - "github.com/jfrazelle/go/canonical/json" + "github.com/docker/go/canonical/json" ) // SignedTimestamp is a fully unpacked timestamp.json diff --git a/vendor/src/github.com/docker/notary/tuf/data/types.go b/vendor/src/github.com/docker/notary/tuf/data/types.go index 61a311664f..6459b8e664 100644 --- a/vendor/src/github.com/docker/notary/tuf/data/types.go +++ b/vendor/src/github.com/docker/notary/tuf/data/types.go @@ -11,7 +11,7 @@ import ( "time" "github.com/Sirupsen/logrus" - "github.com/jfrazelle/go/canonical/json" + "github.com/docker/go/canonical/json" ) // SigAlgorithm for types of signatures diff --git a/vendor/src/github.com/docker/notary/tuf/keys/db.go b/vendor/src/github.com/docker/notary/tuf/keys/db.go index 2e27d052cd..92d2ef863e 100644 --- a/vendor/src/github.com/docker/notary/tuf/keys/db.go +++ b/vendor/src/github.com/docker/notary/tuf/keys/db.go @@ -58,6 +58,15 @@ func (db *KeyDB) AddRole(r *data.Role) error { return nil } +// GetAllRoles gets all roles from the database +func (db *KeyDB) GetAllRoles() []*data.Role { + roles := []*data.Role{} + for _, role := range db.roles { + roles = append(roles, role) + } + return roles +} + // GetKey pulls a key out of the database by its ID func (db *KeyDB) GetKey(id string) data.PublicKey { return db.keys[id] diff --git a/vendor/src/github.com/docker/notary/tuf/signed/verify.go b/vendor/src/github.com/docker/notary/tuf/signed/verify.go index 3c1646f81f..9548e4e53d 100644 --- a/vendor/src/github.com/docker/notary/tuf/signed/verify.go +++ b/vendor/src/github.com/docker/notary/tuf/signed/verify.go @@ -6,9 +6,9 @@ import ( "time" "github.com/Sirupsen/logrus" + "github.com/docker/go/canonical/json" "github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/keys" - "github.com/jfrazelle/go/canonical/json" ) // Various basic signing errors diff --git a/vendor/src/github.com/docker/notary/tuf/store/filestore.go b/vendor/src/github.com/docker/notary/tuf/store/filestore.go index 6ce39ed3ec..52e7c8f289 100644 --- a/vendor/src/github.com/docker/notary/tuf/store/filestore.go +++ b/vendor/src/github.com/docker/notary/tuf/store/filestore.go @@ -39,11 +39,14 @@ type FilesystemStore struct { targetsDir string } +func (f *FilesystemStore) getPath(name string) string { + fileName := fmt.Sprintf("%s.%s", name, f.metaExtension) + return filepath.Join(f.metaDir, fileName) +} + // GetMeta returns the meta for the given name (a role) func (f *FilesystemStore) GetMeta(name string, size int64) ([]byte, error) { - fileName := fmt.Sprintf("%s.%s", name, f.metaExtension) - path := filepath.Join(f.metaDir, fileName) - meta, err := ioutil.ReadFile(path) + meta, err := ioutil.ReadFile(f.getPath(name)) if err != nil { if os.IsNotExist(err) { err = ErrMetaNotFound{Resource: name} @@ -66,21 +69,31 @@ func (f *FilesystemStore) SetMultiMeta(metas map[string][]byte) error { // SetMeta sets the meta for a single role func (f *FilesystemStore) SetMeta(name string, meta []byte) error { - fileName := fmt.Sprintf("%s.%s", name, f.metaExtension) - path := filepath.Join(f.metaDir, fileName) + fp := f.getPath(name) // Ensures the parent directories of the file we are about to write exist - err := os.MkdirAll(filepath.Dir(path), 0700) + err := os.MkdirAll(filepath.Dir(fp), 0700) if err != nil { return err } // if something already exists, just delete it and re-write it - os.RemoveAll(path) + os.RemoveAll(fp) // Write the file to disk - if err = ioutil.WriteFile(path, meta, 0600); err != nil { + if err = ioutil.WriteFile(fp, meta, 0600); err != nil { return err } return nil } + +// RemoveAll clears the existing filestore by removing its base directory +func (f *FilesystemStore) RemoveAll() error { + return os.RemoveAll(f.baseDir) +} + +// RemoveMeta removes the metadata for a single role - if the metadata doesn't +// exist, no error is returned +func (f *FilesystemStore) RemoveMeta(name string) error { + return os.RemoveAll(f.getPath(name)) // RemoveAll succeeds if path doesn't exist +} diff --git a/vendor/src/github.com/docker/notary/tuf/store/httpstore.go b/vendor/src/github.com/docker/notary/tuf/store/httpstore.go index ef69a611df..7444a311b9 100644 --- a/vendor/src/github.com/docker/notary/tuf/store/httpstore.go +++ b/vendor/src/github.com/docker/notary/tuf/store/httpstore.go @@ -85,6 +85,9 @@ func NewHTTPStore(baseURL, metaPrefix, metaExtension, targetsPrefix, keyExtensio if !base.IsAbs() { return nil, errors.New("HTTPStore requires an absolute baseURL") } + if roundTrip == nil { + return &OfflineStore{}, nil + } return &HTTPStore{ baseURL: *base, metaPrefix: metaPrefix, @@ -182,6 +185,12 @@ func (s HTTPStore) SetMeta(name string, blob []byte) error { return translateStatusToError(resp, "POST "+name) } +// RemoveMeta always fails, because we should never be able to delete metadata +// remotely +func (s HTTPStore) RemoveMeta(name string) error { + return ErrInvalidOperation{msg: "cannot delete metadata"} +} + // NewMultiPartMetaRequest builds a request with the provided metadata updates // in multipart form func NewMultiPartMetaRequest(url string, metas map[string][]byte) (*http.Request, error) { @@ -227,6 +236,11 @@ func (s HTTPStore) SetMultiMeta(metas map[string][]byte) error { return translateStatusToError(resp, "POST metadata endpoint") } +// RemoveAll in the interface is not supported, admins should use the DeleteHandler endpoint directly to delete remote data for a GUN +func (s HTTPStore) RemoveAll() error { + return errors.New("remove all functionality not supported for HTTPStore") +} + func (s HTTPStore) buildMetaURL(name string) (*url.URL, error) { var filename string if name != "" { diff --git a/vendor/src/github.com/docker/notary/tuf/store/interfaces.go b/vendor/src/github.com/docker/notary/tuf/store/interfaces.go index 13bffccbdb..6d73da8a96 100644 --- a/vendor/src/github.com/docker/notary/tuf/store/interfaces.go +++ b/vendor/src/github.com/docker/notary/tuf/store/interfaces.go @@ -14,6 +14,8 @@ type MetadataStore interface { GetMeta(name string, size int64) ([]byte, error) SetMeta(name string, blob []byte) error SetMultiMeta(map[string][]byte) error + RemoveAll() error + RemoveMeta(name string) error } // PublicKeyStore must be implemented by a key service diff --git a/vendor/src/github.com/docker/notary/tuf/store/memorystore.go b/vendor/src/github.com/docker/notary/tuf/store/memorystore.go index 5d3e44beb3..6072a8c446 100644 --- a/vendor/src/github.com/docker/notary/tuf/store/memorystore.go +++ b/vendor/src/github.com/docker/notary/tuf/store/memorystore.go @@ -54,6 +54,13 @@ func (m *memoryStore) SetMultiMeta(metas map[string][]byte) error { return nil } +// RemoveMeta removes the metadata for a single role - if the metadata doesn't +// exist, no error is returned +func (m *memoryStore) RemoveMeta(name string) error { + delete(m.meta, name) + return nil +} + func (m *memoryStore) GetTarget(path string) (io.ReadCloser, error) { return &utils.NoopCloser{Reader: bytes.NewReader(m.files[path])}, nil } @@ -95,3 +102,11 @@ func (m *memoryStore) Commit(map[string][]byte, bool, map[string]data.Hashes) er func (m *memoryStore) GetKey(role string) ([]byte, error) { return nil, fmt.Errorf("GetKey is not implemented for the memoryStore") } + +// Clear this existing memory store by setting this store as new empty one +func (m *memoryStore) RemoveAll() error { + m.meta = make(map[string][]byte) + m.files = make(map[string][]byte) + m.keys = make(map[string][]data.PrivateKey) + return nil +} diff --git a/vendor/src/github.com/docker/notary/tuf/store/offlinestore.go b/vendor/src/github.com/docker/notary/tuf/store/offlinestore.go index d32e113c0a..b0f057b2b8 100644 --- a/vendor/src/github.com/docker/notary/tuf/store/offlinestore.go +++ b/vendor/src/github.com/docker/notary/tuf/store/offlinestore.go @@ -14,30 +14,40 @@ func (e ErrOffline) Error() string { var err = ErrOffline{} // OfflineStore is to be used as a placeholder for a nil store. It simply -// return ErrOffline for every operation +// returns ErrOffline for every operation type OfflineStore struct{} -// GetMeta return ErrOffline +// GetMeta returns ErrOffline func (es OfflineStore) GetMeta(name string, size int64) ([]byte, error) { return nil, err } -// SetMeta return ErrOffline +// SetMeta returns ErrOffline func (es OfflineStore) SetMeta(name string, blob []byte) error { return err } -// SetMultiMeta return ErrOffline +// SetMultiMeta returns ErrOffline func (es OfflineStore) SetMultiMeta(map[string][]byte) error { return err } -// GetKey return ErrOffline +// RemoveMeta returns ErrOffline +func (es OfflineStore) RemoveMeta(name string) error { + return err +} + +// GetKey returns ErrOffline func (es OfflineStore) GetKey(role string) ([]byte, error) { return nil, err } -// GetTarget return ErrOffline +// GetTarget returns ErrOffline func (es OfflineStore) GetTarget(path string) (io.ReadCloser, error) { return nil, err } + +// RemoveAll return ErrOffline +func (es OfflineStore) RemoveAll() error { + return err +} diff --git a/vendor/src/github.com/docker/notary/tuf/tuf.go b/vendor/src/github.com/docker/notary/tuf/tuf.go index 83e49467fb..96ab7da1d6 100644 --- a/vendor/src/github.com/docker/notary/tuf/tuf.go +++ b/vendor/src/github.com/docker/notary/tuf/tuf.go @@ -173,6 +173,11 @@ func (tr *Repo) RemoveBaseKeys(role string, keyIDs ...string) error { return nil } +// GetAllLoadedRoles returns a list of all role entries loaded in this TUF repo, could be empty +func (tr *Repo) GetAllLoadedRoles() []*data.Role { + return tr.keysDB.GetAllRoles() +} + // GetDelegation finds the role entry representing the provided // role name or ErrInvalidRole func (tr *Repo) GetDelegation(role string) (*data.Role, error) { From 0617521ba2ce160899852bb707c15bae7309f18a Mon Sep 17 00:00:00 2001 From: cyli Date: Tue, 26 Jan 2016 17:52:36 -0800 Subject: [PATCH 3/3] Update integration tests with new error messages, and to use different repos per test. This way we won't encounter any problems with one test using cached data from a different test. Signed-off-by: cyli --- integration-cli/docker_cli_create_test.go | 13 +++++++------ integration-cli/docker_cli_pull_trusted_test.go | 2 +- integration-cli/docker_cli_push_test.go | 6 +++--- integration-cli/docker_cli_run_test.go | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/integration-cli/docker_cli_create_test.go b/integration-cli/docker_cli_create_test.go index 096074c27e..633313e67c 100644 --- a/integration-cli/docker_cli_create_test.go +++ b/integration-cli/docker_cli_create_test.go @@ -301,18 +301,19 @@ func (s *DockerTrustSuite) TestTrustedCreate(c *check.C) { } func (s *DockerTrustSuite) TestUntrustedCreate(c *check.C) { - repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL) + repoName := fmt.Sprintf("%v/dockercliuntrusted/createtest", privateRegistryURL) + withTagName := fmt.Sprintf("%s:latest", repoName) // tag the image and upload it to the private registry - dockerCmd(c, "tag", "busybox", repoName) - dockerCmd(c, "push", repoName) - dockerCmd(c, "rmi", repoName) + dockerCmd(c, "tag", "busybox", withTagName) + dockerCmd(c, "push", withTagName) + dockerCmd(c, "rmi", withTagName) // Try trusted create on untrusted tag - createCmd := exec.Command(dockerBinary, "create", repoName) + createCmd := exec.Command(dockerBinary, "create", withTagName) s.trustedCmd(createCmd) out, _, err := runCommandWithOutput(createCmd) c.Assert(err, check.Not(check.IsNil)) - c.Assert(string(out), checker.Contains, "trust data unavailable. Has a notary repository been initialized?", check.Commentf("Missing expected output on trusted create:\n%s", out)) + c.Assert(string(out), checker.Contains, fmt.Sprintf("does not have trust data for %s", repoName), check.Commentf("Missing expected output on trusted create:\n%s", out)) } diff --git a/integration-cli/docker_cli_pull_trusted_test.go b/integration-cli/docker_cli_pull_trusted_test.go index fbd50b5d96..86868276f1 100644 --- a/integration-cli/docker_cli_pull_trusted_test.go +++ b/integration-cli/docker_cli_pull_trusted_test.go @@ -47,7 +47,7 @@ func (s *DockerTrustSuite) TestTrustedIsolatedPull(c *check.C) { } func (s *DockerTrustSuite) TestUntrustedPull(c *check.C) { - repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL) + repoName := fmt.Sprintf("%v/dockercliuntrusted/pulltest:latest", privateRegistryURL) // tag the image and upload it to the private registry dockerCmd(c, "tag", "busybox", repoName) dockerCmd(c, "push", repoName) diff --git a/integration-cli/docker_cli_push_test.go b/integration-cli/docker_cli_push_test.go index 8702e3d38c..0e6717644d 100644 --- a/integration-cli/docker_cli_push_test.go +++ b/integration-cli/docker_cli_push_test.go @@ -215,7 +215,7 @@ func (s *DockerSchema1RegistrySuite) TestCrossRepositoryLayerPushNotSupported(c } func (s *DockerTrustSuite) TestTrustedPush(c *check.C) { - repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL) + repoName := fmt.Sprintf("%v/dockerclitrusted/pushtest:latest", privateRegistryURL) // tag the image and upload it to the private registry dockerCmd(c, "tag", "busybox", repoName) @@ -267,7 +267,7 @@ func (s *DockerTrustSuite) TestTrustedPushWithDeprecatedEnvPasswords(c *check.C) } func (s *DockerTrustSuite) TestTrustedPushWithFailingServer(c *check.C) { - repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL) + repoName := fmt.Sprintf("%v/dockerclitrusted/failingserver:latest", privateRegistryURL) // tag the image and upload it to the private registry dockerCmd(c, "tag", "busybox", repoName) @@ -279,7 +279,7 @@ func (s *DockerTrustSuite) TestTrustedPushWithFailingServer(c *check.C) { } func (s *DockerTrustSuite) TestTrustedPushWithoutServerAndUntrusted(c *check.C) { - repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL) + repoName := fmt.Sprintf("%v/dockerclitrusted/trustedandnot:latest", privateRegistryURL) // tag the image and upload it to the private registry dockerCmd(c, "tag", "busybox", repoName) diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 4d05ac6dc7..fe25be56a0 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3179,7 +3179,7 @@ func (s *DockerTrustSuite) TestTrustedRun(c *check.C) { func (s *DockerTrustSuite) TestUntrustedRun(c *check.C) { // Windows does not support this functionality testRequires(c, DaemonIsLinux) - repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL) + repoName := fmt.Sprintf("%v/dockercliuntrusted/runtest:latest", privateRegistryURL) // tag the image and upload it to the private registry dockerCmd(c, "tag", "busybox", repoName) dockerCmd(c, "push", repoName)