Skip to content

Commit

Permalink
make cache injectable into NotaryRepository
Browse files Browse the repository at this point in the history
Signed-off-by: David Lawrence <[email protected]> (github: endophage)
  • Loading branch information
David Lawrence committed Oct 7, 2016
1 parent 49571ed commit e346651
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 148 deletions.
16 changes: 8 additions & 8 deletions client/backwards_compatibility_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func Test0Dot1Migration(t *testing.T) {
ts := fullTestServer(t)
defer ts.Close()

_, err = NewNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport,
_, err = NewFileCachedNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport,
passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)

Expand Down Expand Up @@ -133,7 +133,7 @@ func Test0Dot3Migration(t *testing.T) {
ts := fullTestServer(t)
defer ts.Close()

_, err = NewNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport,
_, err = NewFileCachedNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport,
passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)

Expand Down Expand Up @@ -189,7 +189,7 @@ func Test0Dot1RepoFormat(t *testing.T) {
ts := fullTestServer(t)
defer ts.Close()

repo, err := NewNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport,
repo, err := NewFileCachedNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport,
passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)

Expand All @@ -204,7 +204,7 @@ func Test0Dot1RepoFormat(t *testing.T) {

// delete the timestamp metadata, since the server will ignore the uploaded
// one and try to create a new one from scratch, which will be the wrong version
require.NoError(t, repo.fileStore.Remove(data.CanonicalTimestampRole))
require.NoError(t, repo.cache.Remove(data.CanonicalTimestampRole))

// rotate the timestamp key, since the server doesn't have that one
err = repo.RotateKey(data.CanonicalTimestampRole, true)
Expand Down Expand Up @@ -249,7 +249,7 @@ func Test0Dot3RepoFormat(t *testing.T) {
ts := fullTestServer(t)
defer ts.Close()

repo, err := NewNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport,
repo, err := NewFileCachedNotaryRepository(tmpDir, gun, ts.URL, http.DefaultTransport,
passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)

Expand All @@ -263,7 +263,7 @@ func Test0Dot3RepoFormat(t *testing.T) {

// delete the timestamp metadata, since the server will ignore the uploaded
// one and try to create a new one from scratch, which will be the wrong version
require.NoError(t, repo.fileStore.Remove(data.CanonicalTimestampRole))
require.NoError(t, repo.cache.Remove(data.CanonicalTimestampRole))

// rotate the timestamp key, since the server doesn't have that one
err = repo.RotateKey(data.CanonicalTimestampRole, true)
Expand Down Expand Up @@ -315,7 +315,7 @@ func TestDownloading0Dot1RepoFormat(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(repoDir)

repo, err := NewNotaryRepository(repoDir, gun, ts.URL, http.DefaultTransport,
repo, err := NewFileCachedNotaryRepository(repoDir, gun, ts.URL, http.DefaultTransport,
passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)

Expand All @@ -340,7 +340,7 @@ func TestDownloading0Dot3RepoFormat(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(repoDir)

repo, err := NewNotaryRepository(repoDir, gun, ts.URL, http.DefaultTransport,
repo, err := NewFileCachedNotaryRepository(repoDir, gun, ts.URL, http.DefaultTransport,
passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)

Expand Down
111 changes: 48 additions & 63 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,74 +25,67 @@ import (
"github.com/docker/notary/tuf/utils"
)

func init() {
data.SetDefaultExpiryTimes(notary.NotaryDefaultExpiries)
}

// ErrRepoNotInitialized is returned when trying to publish an uninitialized
// notary repository
type ErrRepoNotInitialized struct{}

func (err ErrRepoNotInitialized) Error() string {
return "repository has not been initialized"
}

// ErrInvalidRemoteRole is returned when the server is requested to manage
// a key type that is not permitted
type ErrInvalidRemoteRole struct {
Role string
}

func (err ErrInvalidRemoteRole) Error() string {
return fmt.Sprintf(
"notary does not permit the server managing the %s key", err.Role)
}

// ErrInvalidLocalRole is returned when the client wants to manage
// a key type that is not permitted
type ErrInvalidLocalRole struct {
Role string
}

func (err ErrInvalidLocalRole) Error() string {
return fmt.Sprintf(
"notary does not permit the client managing the %s key", err.Role)
}

// ErrRepositoryNotExist is returned when an action is taken on a remote
// repository that doesn't exist
type ErrRepositoryNotExist struct {
remote string
gun string
}

func (err ErrRepositoryNotExist) Error() string {
return fmt.Sprintf("%s does not have trust data for %s", err.remote, err.gun)
}

const (
tufDir = "tuf"
)

func init() {
data.SetDefaultExpiryTimes(notary.NotaryDefaultExpiries)
}

// NotaryRepository stores all the information needed to operate on a notary
// repository.
type NotaryRepository struct {
baseDir string
gun string
baseURL string
tufRepoPath string
fileStore store.MetadataStore
cache store.MetadataStore
CryptoService signed.CryptoService
tufRepo *tuf.Repo
invalid *tuf.Repo // known data that was parsable but deemed invalid
roundTrip http.RoundTripper
trustPinning trustpinning.TrustPinConfig
}

// NewFileCachedNotaryRepository is a wrapper for NewNotaryRepository that initializes
// a file cache from the provided repository and local config information
func NewFileCachedNotaryRepository(baseDir, gun, baseURL string, rt http.RoundTripper,
retriever notary.PassRetriever, trustPinning trustpinning.TrustPinConfig) (
*NotaryRepository, error) {

cache, err := store.NewFilesystemStore(
filepath.Join(baseDir, tufDir, filepath.FromSlash(gun)),
"metadata",
"json",
)
if err != nil {
return nil, err
}
return NewNotaryRepository(baseDir, gun, baseURL, rt, cache, retriever, trustPinning)
}

// NewNotaryRepository is a helper method that returns a new notary repository.
// It takes the base directory under where all the trust files will be stored
// (This is normally defaults to "~/.notary" or "~/.docker/trust" when enabling
// docker content trust).
func NewNotaryRepository(baseDir, gun, baseURL string, rt http.RoundTripper, cache store.MetadataStore,
retriever notary.PassRetriever, trustPinning trustpinning.TrustPinConfig) (
*NotaryRepository, error) {

keyStores, err := getKeyStores(baseDir, retriever)
if err != nil {
return nil, err
}

return repositoryFromKeystores(baseDir, gun, baseURL, rt, cache,
keyStores, trustPinning)
}

// repositoryFromKeystores is a helper function for NewNotaryRepository that
// takes some basic NotaryRepository parameters as well as keystores (in order
// of usage preference), and returns a NotaryRepository.
func repositoryFromKeystores(baseDir, gun, baseURL string, rt http.RoundTripper,
func repositoryFromKeystores(baseDir, gun, baseURL string, rt http.RoundTripper, cache store.MetadataStore,
keyStores []trustmanager.KeyStore, trustPin trustpinning.TrustPinConfig) (*NotaryRepository, error) {

cryptoService := cryptoservice.NewCryptoService(keyStores...)
Expand All @@ -107,15 +100,7 @@ func repositoryFromKeystores(baseDir, gun, baseURL string, rt http.RoundTripper,
trustPinning: trustPin,
}

fileStore, err := store.NewFilesystemStore(
nRepo.tufRepoPath,
"metadata",
"json",
)
if err != nil {
return nil, err
}
nRepo.fileStore = fileStore
nRepo.cache = cache

return nRepo, nil
}
Expand Down Expand Up @@ -741,7 +726,7 @@ func (r *NotaryRepository) bootstrapRepo() error {
logrus.Debugf("Loading trusted collection.")

for _, role := range data.BaseRoles {
jsonBytes, err := r.fileStore.GetSized(role, store.NoSizeLimit)
jsonBytes, err := r.cache.GetSized(role, store.NoSizeLimit)
if err != nil {
if _, ok := err.(store.ErrMetaNotFound); ok &&
// server snapshots are supported, and server timestamp management
Expand Down Expand Up @@ -773,7 +758,7 @@ func (r *NotaryRepository) saveMetadata(ignoreSnapshot bool) error {
if err != nil {
return err
}
err = r.fileStore.Set(data.CanonicalRootRole, rootJSON)
err = r.cache.Set(data.CanonicalRootRole, rootJSON)
if err != nil {
return err
}
Expand All @@ -794,7 +779,7 @@ func (r *NotaryRepository) saveMetadata(ignoreSnapshot bool) error {
for role, blob := range targetsToSave {
parentDir := filepath.Dir(role)
os.MkdirAll(parentDir, 0755)
r.fileStore.Set(role, blob)
r.cache.Set(role, blob)
}

if ignoreSnapshot {
Expand All @@ -806,7 +791,7 @@ func (r *NotaryRepository) saveMetadata(ignoreSnapshot bool) error {
return err
}

return r.fileStore.Set(data.CanonicalSnapshotRole, snapshotJSON)
return r.cache.Set(data.CanonicalSnapshotRole, snapshotJSON)
}

// returns a properly constructed ErrRepositoryNotExist error based on this
Expand Down Expand Up @@ -877,7 +862,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*TUFClient, e
// during update which will cause us to download a new root and perform a rotation.
// If we have an old root, and it's valid, then we overwrite the newBuilder to be one
// preloaded with the old root or one which uses the old root for trust bootstrapping.
if rootJSON, err := r.fileStore.GetSized(data.CanonicalRootRole, store.NoSizeLimit); err == nil {
if rootJSON, err := r.cache.GetSized(data.CanonicalRootRole, store.NoSizeLimit); err == nil {
// if we can't load the cached root, fail hard because that is how we pin trust
if err := oldBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, true); err != nil {
return nil, err
Expand Down Expand Up @@ -918,7 +903,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*TUFClient, e
return nil, err
}

err = r.fileStore.Set(data.CanonicalRootRole, tmpJSON)
err = r.cache.Set(data.CanonicalRootRole, tmpJSON)
if err != nil {
// if we can't write cache we should still continue, just log error
logrus.Errorf("could not save root to cache: %s", err.Error())
Expand All @@ -932,7 +917,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*TUFClient, e
return nil, ErrRepoNotInitialized{}
}

return NewTUFClient(oldBuilder, newBuilder, remote, r.fileStore), nil
return NewTUFClient(oldBuilder, newBuilder, remote, r.cache), nil
}

// RotateKey removes all existing keys associated with the role, and either
Expand Down
24 changes: 12 additions & 12 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ func createRepoAndKey(t *testing.T, rootType, tempBaseDir, gun, url string) (
*NotaryRepository, *passRoleRecorder, string) {

rec := newRoleRecorder()
repo, err := NewNotaryRepository(
repo, err := NewFileCachedNotaryRepository(
tempBaseDir, gun, url, http.DefaultTransport, rec.retriever, trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)

Expand Down Expand Up @@ -220,7 +220,7 @@ func newRepoToTestRepo(t *testing.T, existingRepo *NotaryRepository, newDir bool
}

rec := newRoleRecorder()
repo, err := NewNotaryRepository(
repo, err := NewFileCachedNotaryRepository(
repoDir, existingRepo.gun, existingRepo.baseURL,
http.DefaultTransport, rec.retriever, trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repository: %s", err)
Expand Down Expand Up @@ -578,15 +578,15 @@ func testInitRepoAttemptsExceeded(t *testing.T, rootType string) {
defer ts.Close()

retriever := passphrase.ConstantRetriever("password")
repo, err := NewNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{})
repo, err := NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)
rootPubKey, err := repo.CryptoService.Create("root", repo.gun, rootType)
require.NoError(t, err, "error generating root key: %s", err)

retriever = passphrase.ConstantRetriever("incorrect password")
// repo.CryptoService’s FileKeyStore caches the unlocked private key, so to test
// private key unlocking we need a new repo instance.
repo, err = NewNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{})
repo, err = NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)
err = repo.Initialize([]string{rootPubKey.ID()})
require.EqualError(t, err, trustmanager.ErrAttemptsExceeded{}.Error())
Expand Down Expand Up @@ -616,14 +616,14 @@ func testInitRepoPasswordInvalid(t *testing.T, rootType string) {
defer ts.Close()

retriever := passphrase.ConstantRetriever("password")
repo, err := NewNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{})
repo, err := NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, retriever, trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)
rootPubKey, err := repo.CryptoService.Create("root", repo.gun, rootType)
require.NoError(t, err, "error generating root key: %s", err)

// repo.CryptoService’s FileKeyStore caches the unlocked private key, so to test
// private key unlocking we need a new repo instance.
repo, err = NewNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, giveUpPassphraseRetriever, trustpinning.TrustPinConfig{})
repo, err = NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport, giveUpPassphraseRetriever, trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)
err = repo.Initialize([]string{rootPubKey.ID()})
require.EqualError(t, err, trustmanager.ErrPasswordInvalid{}.Error())
Expand Down Expand Up @@ -1660,7 +1660,7 @@ func TestPublishUninitializedRepo(t *testing.T) {
require.NoError(t, err)
defer os.RemoveAll(tempBaseDir)

repo, err := NewNotaryRepository(tempBaseDir, gun, ts.URL,
repo, err := NewFileCachedNotaryRepository(tempBaseDir, gun, ts.URL,
http.DefaultTransport, passphraseRetriever, trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repository: %s", err)
err = repo.Publish()
Expand Down Expand Up @@ -1957,7 +1957,7 @@ func testPublishBadMetadata(t *testing.T, roleName string, repo *NotaryRepositor
addTarget(t, repo, "v1", "../fixtures/intermediate-ca.crt")

// readable, but corrupt file
repo.fileStore.Set(roleName, []byte("this isn't JSON"))
repo.cache.Set(roleName, []byte("this isn't JSON"))
err := repo.Publish()
if succeeds {
require.NoError(t, err)
Expand Down Expand Up @@ -2025,7 +2025,7 @@ func TestPublishSnapshotLocalKeysCreatedFirst(t *testing.T) {
func(http.ResponseWriter, *http.Request) { requestMade = true }))
defer ts.Close()

repo, err := NewNotaryRepository(
repo, err := NewFileCachedNotaryRepository(
tempBaseDir, gun, ts.URL, http.DefaultTransport, passphraseRetriever, trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)

Expand Down Expand Up @@ -2930,7 +2930,7 @@ func TestRemoteServerUnavailableNoLocalCache(t *testing.T) {
ts := errorTestServer(t, 500)
defer ts.Close()

repo, err := NewNotaryRepository(tempBaseDir, "docker.com/notary",
repo, err := NewFileCachedNotaryRepository(tempBaseDir, "docker.com/notary",
ts.URL, http.DefaultTransport, passphraseRetriever, trustpinning.TrustPinConfig{})
require.NoError(t, err, "error creating repo: %s", err)

Expand Down Expand Up @@ -3239,7 +3239,7 @@ func TestRemoveDelegationErrorWritingChanges(t *testing.T) {
func TestBootstrapClientBadURL(t *testing.T) {
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
require.NoError(t, err, "failed to create a temporary directory: %s", err)
repo, err := NewNotaryRepository(
repo, err := NewFileCachedNotaryRepository(
tempBaseDir,
"testGun",
"http://localhost:9998",
Expand Down Expand Up @@ -3269,7 +3269,7 @@ func TestBootstrapClientBadURL(t *testing.T) {
func TestBootstrapClientInvalidURL(t *testing.T) {
tempBaseDir, err := ioutil.TempDir("", "notary-test-")
require.NoError(t, err, "failed to create a temporary directory: %s", err)
repo, err := NewNotaryRepository(
repo, err := NewFileCachedNotaryRepository(
tempBaseDir,
"testGun",
"#!*)&!)#*^%!#)%^!#",
Expand Down
Loading

0 comments on commit e346651

Please sign in to comment.