mirror of https://github.com/docker/cli.git
trust: add Repository client interface
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
parent
45c102a03d
commit
7c5b836ca5
|
@ -109,18 +109,19 @@ func PushTrustedReference(streams command.Streams, repoInfo *registry.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the latest repository metadata so we can figure out which roles to sign
|
// get the latest repository metadata so we can figure out which roles to sign
|
||||||
err = repo.Update(false)
|
// TODO(riyazdf): interface change to get back Update
|
||||||
|
_, err = repo.ListTargets()
|
||||||
|
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
|
case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
|
||||||
keys := repo.CryptoService.ListKeys(data.CanonicalRootRole)
|
keys := repo.GetCryptoService().ListKeys(data.CanonicalRootRole)
|
||||||
var rootKeyID string
|
var rootKeyID string
|
||||||
// always select the first root key
|
// always select the first root key
|
||||||
if len(keys) > 0 {
|
if len(keys) > 0 {
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
rootKeyID = keys[0]
|
rootKeyID = keys[0]
|
||||||
} else {
|
} else {
|
||||||
rootPublicKey, err := repo.CryptoService.Create(data.CanonicalRootRole, "", data.ECDSAKey)
|
rootPublicKey, err := repo.GetCryptoService().Create(data.CanonicalRootRole, "", data.ECDSAKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -157,7 +158,7 @@ func PushTrustedReference(streams command.Streams, repoInfo *registry.Repository
|
||||||
// (based on whether we have the signing key and whether the role's path allows
|
// (based on whether we have the signing key and whether the role's path allows
|
||||||
// us to).
|
// us to).
|
||||||
// If there are no delegation roles, we add to the targets role.
|
// If there are no delegation roles, we add to the targets role.
|
||||||
func AddTargetToAllSignableRoles(repo *client.NotaryRepository, target *client.Target) error {
|
func AddTargetToAllSignableRoles(repo client.Repository, target *client.Target) error {
|
||||||
signableRoles, err := trust.GetSignableRoles(repo, target)
|
signableRoles, err := trust.GetSignableRoles(repo, target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -66,7 +66,7 @@ func TestAddTargetToAllSignableRolesError(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
|
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
|
||||||
target := client.Target{}
|
target := client.Target{}
|
||||||
err = AddTargetToAllSignableRoles(notaryRepo, &target)
|
err = AddTargetToAllSignableRoles(notaryRepo, &target)
|
||||||
assert.EqualError(t, err, "client is offline")
|
assert.EqualError(t, err, "client is offline")
|
||||||
|
@ -77,7 +77,7 @@ func TestGetSignableRolesError(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
|
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
|
||||||
target := client.Target{}
|
target := client.Target{}
|
||||||
_, err = trust.GetSignableRoles(notaryRepo, &target)
|
_, err = trust.GetSignableRoles(notaryRepo, &target)
|
||||||
assert.EqualError(t, err, "client is offline")
|
assert.EqualError(t, err, "client is offline")
|
||||||
|
|
|
@ -92,7 +92,7 @@ func notaryRoleToSigner(tufRole data.RoleName) string {
|
||||||
return strings.TrimPrefix(tufRole.String(), "targets/")
|
return strings.TrimPrefix(tufRole.String(), "targets/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearChangeList(notaryRepo *client.NotaryRepository) error {
|
func clearChangeList(notaryRepo client.Repository) error {
|
||||||
cl, err := notaryRepo.GetChangelist()
|
cl, err := notaryRepo.GetChangelist()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/cli/cli"
|
"github.com/docker/cli/cli"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
"github.com/docker/cli/cli/command/formatter"
|
"github.com/docker/cli/cli/command/formatter"
|
||||||
|
@ -16,6 +15,7 @@ import (
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/client"
|
"github.com/docker/notary/client"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ func revokeTrust(cli command.Cli, remote string, options revokeOptions) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func revokeSignature(notaryRepo *client.NotaryRepository, tag string) error {
|
func revokeSignature(notaryRepo client.Repository, tag string) error {
|
||||||
if tag != "" {
|
if tag != "" {
|
||||||
// Revoke signature for the specified tag
|
// Revoke signature for the specified tag
|
||||||
if err := revokeSingleSig(notaryRepo, tag); err != nil {
|
if err := revokeSingleSig(notaryRepo, tag); err != nil {
|
||||||
|
@ -82,7 +82,7 @@ func revokeSignature(notaryRepo *client.NotaryRepository, tag string) error {
|
||||||
return notaryRepo.Publish()
|
return notaryRepo.Publish()
|
||||||
}
|
}
|
||||||
|
|
||||||
func revokeSingleSig(notaryRepo *client.NotaryRepository, tag string) error {
|
func revokeSingleSig(notaryRepo client.Repository, tag string) error {
|
||||||
releasedTargetWithRole, err := notaryRepo.GetTargetByName(tag, trust.ReleasesRole, data.CanonicalTargetsRole)
|
releasedTargetWithRole, err := notaryRepo.GetTargetByName(tag, trust.ReleasesRole, data.CanonicalTargetsRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -91,7 +91,7 @@ func revokeSingleSig(notaryRepo *client.NotaryRepository, tag string) error {
|
||||||
return getSignableRolesForTargetAndRemove(releasedTarget, notaryRepo)
|
return getSignableRolesForTargetAndRemove(releasedTarget, notaryRepo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func revokeAllSigs(notaryRepo *client.NotaryRepository) error {
|
func revokeAllSigs(notaryRepo client.Repository) error {
|
||||||
releasedTargetWithRoleList, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
|
releasedTargetWithRoleList, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -108,7 +108,7 @@ func revokeAllSigs(notaryRepo *client.NotaryRepository) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all the roles that signed the target and removes it from all roles.
|
// get all the roles that signed the target and removes it from all roles.
|
||||||
func getSignableRolesForTargetAndRemove(releasedTarget client.Target, notaryRepo *client.NotaryRepository) error {
|
func getSignableRolesForTargetAndRemove(releasedTarget client.Target, notaryRepo client.Repository) error {
|
||||||
signableRoles, err := trust.GetSignableRoles(notaryRepo, &releasedTarget)
|
signableRoles, err := trust.GetSignableRoles(notaryRepo, &releasedTarget)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -86,7 +86,7 @@ func TestGetSignableRolesForTargetAndRemoveError(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
|
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
|
||||||
target := client.Target{}
|
target := client.Target{}
|
||||||
err = getSignableRolesForTargetAndRemove(target, notaryRepo)
|
err = getSignableRolesForTargetAndRemove(target, notaryRepo)
|
||||||
assert.EqualError(t, err, "client is offline")
|
assert.EqualError(t, err, "client is offline")
|
||||||
|
|
|
@ -50,7 +50,8 @@ func signImage(cli command.Cli, imageName string) error {
|
||||||
defer clearChangeList(notaryRepo)
|
defer clearChangeList(notaryRepo)
|
||||||
|
|
||||||
// get the latest repository metadata so we can figure out which roles to sign
|
// get the latest repository metadata so we can figure out which roles to sign
|
||||||
if err = notaryRepo.Update(false); err != nil {
|
// TODO(riyazdf): interface change to get back Update
|
||||||
|
if _, err = notaryRepo.ListTargets(); err != nil {
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
|
case client.ErrRepoNotInitialized, client.ErrRepositoryNotExist:
|
||||||
// before initializing a new repo, check that the image exists locally:
|
// before initializing a new repo, check that the image exists locally:
|
||||||
|
@ -106,7 +107,7 @@ func checkLocalImageExistence(ctx context.Context, cli command.Cli, imageName st
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTarget(notaryRepo *client.NotaryRepository, tag string) (client.Target, error) {
|
func createTarget(notaryRepo client.Repository, tag string) (client.Target, error) {
|
||||||
target := &client.Target{}
|
target := &client.Target{}
|
||||||
var err error
|
var err error
|
||||||
if tag == "" {
|
if tag == "" {
|
||||||
|
@ -117,7 +118,7 @@ func createTarget(notaryRepo *client.NotaryRepository, tag string) (client.Targe
|
||||||
return *target, err
|
return *target, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSignedManifestHashAndSize(notaryRepo *client.NotaryRepository, tag string) (data.Hashes, int64, error) {
|
func getSignedManifestHashAndSize(notaryRepo client.Repository, tag string) (data.Hashes, int64, error) {
|
||||||
targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
|
targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
|
@ -134,7 +135,7 @@ func getReleasedTargetHashAndSize(targets []client.TargetSignedStruct, tag strin
|
||||||
return nil, 0, client.ErrNoSuchTarget(tag)
|
return nil, 0, client.ErrNoSuchTarget(tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getExistingSignatureInfoForReleasedTag(notaryRepo *client.NotaryRepository, tag string) (trustTagRow, error) {
|
func getExistingSignatureInfoForReleasedTag(notaryRepo client.Repository, tag string) (trustTagRow, error) {
|
||||||
targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
|
targets, err := notaryRepo.GetAllTargetMetadataByName(tag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return trustTagRow{}, err
|
return trustTagRow{}, err
|
||||||
|
@ -152,7 +153,7 @@ func prettyPrintExistingSignatureInfo(cli command.Cli, existingSigInfo trustTagR
|
||||||
fmt.Fprintf(cli.Out(), "Existing signatures for tag %s digest %s from:\n%s\n", existingSigInfo.TagName, existingSigInfo.HashHex, joinedSigners)
|
fmt.Fprintf(cli.Out(), "Existing signatures for tag %s digest %s from:\n%s\n", existingSigInfo.TagName, existingSigInfo.HashHex, joinedSigners)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initNotaryRepoWithSigners(notaryRepo *client.NotaryRepository, newSigner data.RoleName) error {
|
func initNotaryRepoWithSigners(notaryRepo client.Repository, newSigner data.RoleName) error {
|
||||||
rootKey, err := getOrGenerateNotaryKey(notaryRepo, data.CanonicalRootRole)
|
rootKey, err := getOrGenerateNotaryKey(notaryRepo, data.CanonicalRootRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -174,25 +175,25 @@ func initNotaryRepoWithSigners(notaryRepo *client.NotaryRepository, newSigner da
|
||||||
}
|
}
|
||||||
|
|
||||||
// generates an ECDSA key without a GUN for the specified role
|
// generates an ECDSA key without a GUN for the specified role
|
||||||
func getOrGenerateNotaryKey(notaryRepo *client.NotaryRepository, role data.RoleName) (data.PublicKey, error) {
|
func getOrGenerateNotaryKey(notaryRepo client.Repository, role data.RoleName) (data.PublicKey, error) {
|
||||||
// use the signer name in the PEM headers if this is a delegation key
|
// use the signer name in the PEM headers if this is a delegation key
|
||||||
if data.IsDelegation(role) {
|
if data.IsDelegation(role) {
|
||||||
role = data.RoleName(notaryRoleToSigner(role))
|
role = data.RoleName(notaryRoleToSigner(role))
|
||||||
}
|
}
|
||||||
keys := notaryRepo.CryptoService.ListKeys(role)
|
keys := notaryRepo.GetCryptoService().ListKeys(role)
|
||||||
var err error
|
var err error
|
||||||
var key data.PublicKey
|
var key data.PublicKey
|
||||||
// always select the first key by ID
|
// always select the first key by ID
|
||||||
if len(keys) > 0 {
|
if len(keys) > 0 {
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
keyID := keys[0]
|
keyID := keys[0]
|
||||||
privKey, _, err := notaryRepo.CryptoService.GetPrivateKey(keyID)
|
privKey, _, err := notaryRepo.GetCryptoService().GetPrivateKey(keyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
key = data.PublicKeyFromPrivate(privKey)
|
key = data.PublicKeyFromPrivate(privKey)
|
||||||
} else {
|
} else {
|
||||||
key, err = notaryRepo.CryptoService.Create(role, "", data.ECDSAKey)
|
key, err = notaryRepo.GetCryptoService().Create(role, "", data.ECDSAKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -201,7 +202,7 @@ func getOrGenerateNotaryKey(notaryRepo *client.NotaryRepository, role data.RoleN
|
||||||
}
|
}
|
||||||
|
|
||||||
// stages changes to add a signer with the specified name and key(s). Adds to targets/<name> and targets/releases
|
// stages changes to add a signer with the specified name and key(s). Adds to targets/<name> and targets/releases
|
||||||
func addStagedSigner(notaryRepo *client.NotaryRepository, newSigner data.RoleName, signerKeys []data.PublicKey) {
|
func addStagedSigner(notaryRepo client.Repository, newSigner data.RoleName, signerKeys []data.PublicKey) {
|
||||||
// create targets/<username>
|
// create targets/<username>
|
||||||
notaryRepo.AddDelegationRoleAndKeys(newSigner, signerKeys)
|
notaryRepo.AddDelegationRoleAndKeys(newSigner, signerKeys)
|
||||||
notaryRepo.AddDelegationPaths(newSigner, []string{""})
|
notaryRepo.AddDelegationPaths(newSigner, []string{""})
|
||||||
|
|
|
@ -91,7 +91,7 @@ func TestGetOrGenerateNotaryKey(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// repo is empty, try making a root key
|
// repo is empty, try making a root key
|
||||||
|
@ -100,9 +100,9 @@ func TestGetOrGenerateNotaryKey(t *testing.T) {
|
||||||
assert.NotNil(t, rootKeyA)
|
assert.NotNil(t, rootKeyA)
|
||||||
|
|
||||||
// we should only have one newly generated key
|
// we should only have one newly generated key
|
||||||
allKeys := notaryRepo.CryptoService.ListAllKeys()
|
allKeys := notaryRepo.GetCryptoService().ListAllKeys()
|
||||||
assert.Len(t, allKeys, 1)
|
assert.Len(t, allKeys, 1)
|
||||||
assert.NotNil(t, notaryRepo.CryptoService.GetKey(rootKeyA.ID()))
|
assert.NotNil(t, notaryRepo.GetCryptoService().GetKey(rootKeyA.ID()))
|
||||||
|
|
||||||
// this time we should get back the same key if we ask for another root key
|
// this time we should get back the same key if we ask for another root key
|
||||||
rootKeyB, err := getOrGenerateNotaryKey(notaryRepo, data.CanonicalRootRole)
|
rootKeyB, err := getOrGenerateNotaryKey(notaryRepo, data.CanonicalRootRole)
|
||||||
|
@ -110,9 +110,9 @@ func TestGetOrGenerateNotaryKey(t *testing.T) {
|
||||||
assert.NotNil(t, rootKeyB)
|
assert.NotNil(t, rootKeyB)
|
||||||
|
|
||||||
// we should only have one newly generated key
|
// we should only have one newly generated key
|
||||||
allKeys = notaryRepo.CryptoService.ListAllKeys()
|
allKeys = notaryRepo.GetCryptoService().ListAllKeys()
|
||||||
assert.Len(t, allKeys, 1)
|
assert.Len(t, allKeys, 1)
|
||||||
assert.NotNil(t, notaryRepo.CryptoService.GetKey(rootKeyB.ID()))
|
assert.NotNil(t, notaryRepo.GetCryptoService().GetKey(rootKeyB.ID()))
|
||||||
|
|
||||||
// The key we retrieved should be identical to the one we generated
|
// The key we retrieved should be identical to the one we generated
|
||||||
assert.Equal(t, rootKeyA, rootKeyB)
|
assert.Equal(t, rootKeyA, rootKeyB)
|
||||||
|
@ -123,9 +123,9 @@ func TestGetOrGenerateNotaryKey(t *testing.T) {
|
||||||
assert.NotNil(t, releasesKey)
|
assert.NotNil(t, releasesKey)
|
||||||
|
|
||||||
// we should now have two keys
|
// we should now have two keys
|
||||||
allKeys = notaryRepo.CryptoService.ListAllKeys()
|
allKeys = notaryRepo.GetCryptoService().ListAllKeys()
|
||||||
assert.Len(t, allKeys, 2)
|
assert.Len(t, allKeys, 2)
|
||||||
assert.NotNil(t, notaryRepo.CryptoService.GetKey(releasesKey.ID()))
|
assert.NotNil(t, notaryRepo.GetCryptoService().GetKey(releasesKey.ID()))
|
||||||
// The key we retrieved should be identical to the one we generated
|
// The key we retrieved should be identical to the one we generated
|
||||||
assert.NotEqual(t, releasesKey, rootKeyA)
|
assert.NotEqual(t, releasesKey, rootKeyA)
|
||||||
assert.NotEqual(t, releasesKey, rootKeyB)
|
assert.NotEqual(t, releasesKey, rootKeyB)
|
||||||
|
@ -136,7 +136,7 @@ func TestAddStageSigners(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// stage targets/user
|
// stage targets/user
|
||||||
|
@ -216,7 +216,7 @@ func TestGetSignedManifestHashAndSize(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
target := &client.Target{}
|
target := &client.Target{}
|
||||||
target.Hashes, target.Length, err = getSignedManifestHashAndSize(notaryRepo, "test")
|
target.Hashes, target.Length, err = getSignedManifestHashAndSize(notaryRepo, "test")
|
||||||
|
@ -244,7 +244,7 @@ func TestCreateTarget(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, err = createTarget(notaryRepo, "")
|
_, err = createTarget(notaryRepo, "")
|
||||||
assert.EqualError(t, err, "No tag specified")
|
assert.EqualError(t, err, "No tag specified")
|
||||||
|
@ -257,7 +257,7 @@ func TestGetExistingSignatureInfoForReleasedTag(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
_, err = getExistingSignatureInfoForReleasedTag(notaryRepo, "test")
|
_, err = getExistingSignatureInfoForReleasedTag(notaryRepo, "test")
|
||||||
assert.EqualError(t, err, "client is offline")
|
assert.EqualError(t, err, "client is offline")
|
||||||
|
@ -284,7 +284,7 @@ func TestChangeList(t *testing.T) {
|
||||||
cmd.SetArgs([]string{"ubuntu:latest"})
|
cmd.SetArgs([]string{"ubuntu:latest"})
|
||||||
cmd.SetOutput(ioutil.Discard)
|
cmd.SetOutput(ioutil.Discard)
|
||||||
err = cmd.Execute()
|
err = cmd.Execute()
|
||||||
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "docker.io/library/ubuntu", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "docker.io/library/ubuntu", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
cl, err := notaryRepo.GetChangelist()
|
cl, err := notaryRepo.GetChangelist()
|
||||||
assert.Equal(t, len(cl.List()), 0)
|
assert.Equal(t, len(cl.List()), 0)
|
||||||
|
|
|
@ -86,7 +86,7 @@ func (scs simpleCredentialStore) SetRefreshToken(*url.URL, string, string) {
|
||||||
// GetNotaryRepository returns a NotaryRepository which stores all the
|
// GetNotaryRepository returns a NotaryRepository which stores all the
|
||||||
// information needed to operate on a notary repository.
|
// information needed to operate on a notary repository.
|
||||||
// It creates an HTTP transport providing authentication support.
|
// It creates an HTTP transport providing authentication support.
|
||||||
func GetNotaryRepository(streams command.Streams, repoInfo *registry.RepositoryInfo, authConfig types.AuthConfig, actions ...string) (*client.NotaryRepository, error) {
|
func GetNotaryRepository(streams command.Streams, repoInfo *registry.RepositoryInfo, authConfig types.AuthConfig, actions ...string) (client.Repository, error) {
|
||||||
server, err := Server(repoInfo.Index)
|
server, err := Server(repoInfo.Index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -164,7 +164,7 @@ func GetNotaryRepository(streams command.Streams, repoInfo *registry.RepositoryI
|
||||||
modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
|
modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
|
||||||
tr := transport.NewTransport(base, modifiers...)
|
tr := transport.NewTransport(base, modifiers...)
|
||||||
|
|
||||||
return client.NewFileCachedNotaryRepository(
|
return client.NewFileCachedRepository(
|
||||||
trustDirectory(),
|
trustDirectory(),
|
||||||
data.GUN(repoInfo.Name.Name()),
|
data.GUN(repoInfo.Name.Name()),
|
||||||
server,
|
server,
|
||||||
|
@ -233,12 +233,12 @@ func NotaryError(repoName string, err error) error {
|
||||||
|
|
||||||
// GetSignableRoles returns a list of roles for which we have valid signing
|
// GetSignableRoles returns a list of roles for which we have valid signing
|
||||||
// keys, given a notary repository and a target
|
// keys, given a notary repository and a target
|
||||||
func GetSignableRoles(repo *client.NotaryRepository, target *client.Target) ([]data.RoleName, error) {
|
func GetSignableRoles(repo client.Repository, target *client.Target) ([]data.RoleName, error) {
|
||||||
var signableRoles []data.RoleName
|
var signableRoles []data.RoleName
|
||||||
|
|
||||||
// translate the full key names, which includes the GUN, into just the key IDs
|
// translate the full key names, which includes the GUN, into just the key IDs
|
||||||
allCanonicalKeyIDs := make(map[string]struct{})
|
allCanonicalKeyIDs := make(map[string]struct{})
|
||||||
for fullKeyID := range repo.CryptoService.ListAllKeys() {
|
for fullKeyID := range repo.GetCryptoService().ListAllKeys() {
|
||||||
allCanonicalKeyIDs[path.Base(fullKeyID)] = struct{}{}
|
allCanonicalKeyIDs[path.Base(fullKeyID)] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
|
||||||
github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
|
github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
|
||||||
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||||
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
||||||
github.com/docker/notary e8ee47e98edf5bb12c29735c5941fa6e482dcd9f
|
github.com/docker/notary 8a1de3cfc3f1408e54d6364fc949214a4883a9f3
|
||||||
github.com/docker/swarmkit 79381d0840be27f8b3f5c667b348a4467d866eeb
|
github.com/docker/swarmkit 79381d0840be27f8b3f5c667b348a4467d866eeb
|
||||||
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
|
github.com/flynn-archive/go-shlex 3f9db97f856818214da2e1057f8ad84803971cff
|
||||||
github.com/gogo/protobuf v0.4
|
github.com/gogo/protobuf v0.4
|
||||||
|
|
|
@ -5,12 +5,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/distribution/uuid"
|
"github.com/docker/distribution/uuid"
|
||||||
"path/filepath"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileChangelist stores all the changes as files
|
// FileChangelist stores all the changes as files
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
canonicaljson "github.com/docker/go/canonical/json"
|
canonicaljson "github.com/docker/go/canonical/json"
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/client/changelist"
|
"github.com/docker/notary/client/changelist"
|
||||||
|
@ -23,6 +22,7 @@ import (
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/signed"
|
"github.com/docker/notary/tuf/signed"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -36,16 +36,15 @@ func init() {
|
||||||
data.SetDefaultExpiryTimes(data.NotaryDefaultExpiries)
|
data.SetDefaultExpiryTimes(data.NotaryDefaultExpiries)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotaryRepository stores all the information needed to operate on a notary
|
// repository stores all the information needed to operate on a notary repository.
|
||||||
// repository.
|
type repository struct {
|
||||||
type NotaryRepository struct {
|
|
||||||
baseDir string
|
baseDir string
|
||||||
gun data.GUN
|
gun data.GUN
|
||||||
baseURL string
|
baseURL string
|
||||||
changelist changelist.Changelist
|
changelist changelist.Changelist
|
||||||
cache store.MetadataStore
|
cache store.MetadataStore
|
||||||
remoteStore store.RemoteStore
|
remoteStore store.RemoteStore
|
||||||
CryptoService signed.CryptoService
|
cryptoService signed.CryptoService
|
||||||
tufRepo *tuf.Repo
|
tufRepo *tuf.Repo
|
||||||
invalid *tuf.Repo // known data that was parsable but deemed invalid
|
invalid *tuf.Repo // known data that was parsable but deemed invalid
|
||||||
roundTrip http.RoundTripper
|
roundTrip http.RoundTripper
|
||||||
|
@ -53,15 +52,14 @@ type NotaryRepository struct {
|
||||||
LegacyVersions int // number of versions back to fetch roots to sign with
|
LegacyVersions int // number of versions back to fetch roots to sign with
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileCachedNotaryRepository is a wrapper for NewNotaryRepository that initializes
|
// NewFileCachedRepository is a wrapper for NewRepository that initializes
|
||||||
// a file cache from the provided repository, local config information and a crypto service.
|
// a file cache from the provided repository, local config information and a crypto service.
|
||||||
// It also retrieves the remote store associated to the base directory under where all the
|
// It also retrieves the remote store associated to the base directory under where all the
|
||||||
// trust files will be stored and the specified GUN.
|
// trust files will be stored and the specified GUN.
|
||||||
//
|
//
|
||||||
// In case of a nil RoundTripper, a default offline store is used instead.
|
// In case of a nil RoundTripper, a default offline store is used instead.
|
||||||
func NewFileCachedNotaryRepository(baseDir string, gun data.GUN, baseURL string, rt http.RoundTripper,
|
func NewFileCachedRepository(baseDir string, gun data.GUN, baseURL string, rt http.RoundTripper,
|
||||||
retriever notary.PassRetriever, trustPinning trustpinning.TrustPinConfig) (
|
retriever notary.PassRetriever, trustPinning trustpinning.TrustPinConfig) (Repository, error) {
|
||||||
*NotaryRepository, error) {
|
|
||||||
|
|
||||||
cache, err := store.NewFileStore(
|
cache, err := store.NewFileStore(
|
||||||
filepath.Join(baseDir, tufDir, filepath.FromSlash(gun.String()), "metadata"),
|
filepath.Join(baseDir, tufDir, filepath.FromSlash(gun.String()), "metadata"),
|
||||||
|
@ -91,18 +89,17 @@ func NewFileCachedNotaryRepository(baseDir string, gun data.GUN, baseURL string,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewNotaryRepository(baseDir, gun, baseURL, remoteStore, cache, trustPinning, cryptoService, cl)
|
return NewRepository(baseDir, gun, baseURL, remoteStore, cache, trustPinning, cryptoService, cl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNotaryRepository is the base method that returns a new notary repository.
|
// NewRepository is the base method that returns a new notary repository.
|
||||||
// It takes the base directory under where all the trust files will be stored
|
// 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
|
// (This is normally defaults to "~/.notary" or "~/.docker/trust" when enabling
|
||||||
// docker content trust).
|
// docker content trust).
|
||||||
// It expects an initialized cache. In case of a nil remote store, a default
|
// It expects an initialized cache. In case of a nil remote store, a default
|
||||||
// offline store is used.
|
// offline store is used.
|
||||||
func NewNotaryRepository(baseDir string, gun data.GUN, baseURL string, remoteStore store.RemoteStore, cache store.MetadataStore,
|
func NewRepository(baseDir string, gun data.GUN, baseURL string, remoteStore store.RemoteStore, cache store.MetadataStore,
|
||||||
trustPinning trustpinning.TrustPinConfig, cryptoService signed.CryptoService, cl changelist.Changelist) (
|
trustPinning trustpinning.TrustPinConfig, cryptoService signed.CryptoService, cl changelist.Changelist) (Repository, error) {
|
||||||
*NotaryRepository, error) {
|
|
||||||
|
|
||||||
// Repo's remote store is either a valid remote store or an OfflineStore
|
// Repo's remote store is either a valid remote store or an OfflineStore
|
||||||
if remoteStore == nil {
|
if remoteStore == nil {
|
||||||
|
@ -113,14 +110,14 @@ func NewNotaryRepository(baseDir string, gun data.GUN, baseURL string, remoteSto
|
||||||
return nil, fmt.Errorf("got an invalid cache (nil metadata store)")
|
return nil, fmt.Errorf("got an invalid cache (nil metadata store)")
|
||||||
}
|
}
|
||||||
|
|
||||||
nRepo := &NotaryRepository{
|
nRepo := &repository{
|
||||||
gun: gun,
|
gun: gun,
|
||||||
baseURL: baseURL,
|
baseURL: baseURL,
|
||||||
baseDir: baseDir,
|
baseDir: baseDir,
|
||||||
changelist: cl,
|
changelist: cl,
|
||||||
cache: cache,
|
cache: cache,
|
||||||
remoteStore: remoteStore,
|
remoteStore: remoteStore,
|
||||||
CryptoService: cryptoService,
|
cryptoService: cryptoService,
|
||||||
trustPinning: trustPinning,
|
trustPinning: trustPinning,
|
||||||
LegacyVersions: 0, // By default, don't sign with legacy roles
|
LegacyVersions: 0, // By default, don't sign with legacy roles
|
||||||
}
|
}
|
||||||
|
@ -128,8 +125,8 @@ func NewNotaryRepository(baseDir string, gun data.GUN, baseURL string, remoteSto
|
||||||
return nRepo, nil
|
return nRepo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGUN is a getter for the GUN object from a NotaryRepository
|
// GetGUN is a getter for the GUN object from a Repository
|
||||||
func (r *NotaryRepository) GetGUN() data.GUN {
|
func (r *repository) GetGUN() data.GUN {
|
||||||
return r.gun
|
return r.gun
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,8 +179,13 @@ func rootCertKey(gun data.GUN, privKey data.PrivateKey) (data.PublicKey, error)
|
||||||
return x509PublicKey, nil
|
return x509PublicKey, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCryptoService is the getter for the repository's CryptoService
|
||||||
|
func (r *repository) GetCryptoService() signed.CryptoService {
|
||||||
|
return r.cryptoService
|
||||||
|
}
|
||||||
|
|
||||||
// initialize initializes the notary repository with a set of rootkeys, root certificates and roles.
|
// initialize initializes the notary repository with a set of rootkeys, root certificates and roles.
|
||||||
func (r *NotaryRepository) initialize(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error {
|
func (r *repository) initialize(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error {
|
||||||
|
|
||||||
// currently we only support server managing timestamps and snapshots, and
|
// currently we only support server managing timestamps and snapshots, and
|
||||||
// nothing else - timestamps are always managed by the server, and implicit
|
// nothing else - timestamps are always managed by the server, and implicit
|
||||||
|
@ -234,7 +236,7 @@ func (r *NotaryRepository) initialize(rootKeyIDs []string, rootCerts []data.Publ
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
r.tufRepo = tuf.NewRepo(r.CryptoService)
|
r.tufRepo = tuf.NewRepo(r.GetCryptoService())
|
||||||
|
|
||||||
if err := r.tufRepo.InitRoot(
|
if err := r.tufRepo.InitRoot(
|
||||||
rootRole,
|
rootRole,
|
||||||
|
@ -261,10 +263,10 @@ func (r *NotaryRepository) initialize(rootKeyIDs []string, rootCerts []data.Publ
|
||||||
// createNewPublicKeyFromKeyIDs generates a set of public keys corresponding to the given list of
|
// createNewPublicKeyFromKeyIDs generates a set of public keys corresponding to the given list of
|
||||||
// key IDs existing in the repository's CryptoService.
|
// key IDs existing in the repository's CryptoService.
|
||||||
// the public keys returned are ordered to correspond to the keyIDs
|
// the public keys returned are ordered to correspond to the keyIDs
|
||||||
func (r *NotaryRepository) createNewPublicKeyFromKeyIDs(keyIDs []string) ([]data.PublicKey, error) {
|
func (r *repository) createNewPublicKeyFromKeyIDs(keyIDs []string) ([]data.PublicKey, error) {
|
||||||
publicKeys := []data.PublicKey{}
|
publicKeys := []data.PublicKey{}
|
||||||
|
|
||||||
privKeys, err := getAllPrivKeys(keyIDs, r.CryptoService)
|
privKeys, err := getAllPrivKeys(keyIDs, r.GetCryptoService())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -282,7 +284,7 @@ func (r *NotaryRepository) createNewPublicKeyFromKeyIDs(keyIDs []string) ([]data
|
||||||
// publicKeysOfKeyIDs confirms that the public key and private keys (by Key IDs) forms valid, strictly ordered key pairs
|
// publicKeysOfKeyIDs confirms that the public key and private keys (by Key IDs) forms valid, strictly ordered key pairs
|
||||||
// (eg. keyIDs[0] must match pubKeys[0] and keyIDs[1] must match certs[1] and so on).
|
// (eg. keyIDs[0] must match pubKeys[0] and keyIDs[1] must match certs[1] and so on).
|
||||||
// Or throw error when they mismatch.
|
// Or throw error when they mismatch.
|
||||||
func (r *NotaryRepository) publicKeysOfKeyIDs(keyIDs []string, pubKeys []data.PublicKey) ([]data.PublicKey, error) {
|
func (r *repository) publicKeysOfKeyIDs(keyIDs []string, pubKeys []data.PublicKey) ([]data.PublicKey, error) {
|
||||||
if len(keyIDs) != len(pubKeys) {
|
if len(keyIDs) != len(pubKeys) {
|
||||||
err := fmt.Errorf("require matching number of keyIDs and public keys but got %d IDs and %d public keys", len(keyIDs), len(pubKeys))
|
err := fmt.Errorf("require matching number of keyIDs and public keys but got %d IDs and %d public keys", len(keyIDs), len(pubKeys))
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -296,9 +298,9 @@ func (r *NotaryRepository) publicKeysOfKeyIDs(keyIDs []string, pubKeys []data.Pu
|
||||||
|
|
||||||
// matchKeyIdsWithPubKeys validates that the private keys (represented by their IDs) and the public keys
|
// matchKeyIdsWithPubKeys validates that the private keys (represented by their IDs) and the public keys
|
||||||
// forms matching key pairs
|
// forms matching key pairs
|
||||||
func matchKeyIdsWithPubKeys(r *NotaryRepository, ids []string, pubKeys []data.PublicKey) error {
|
func matchKeyIdsWithPubKeys(r *repository, ids []string, pubKeys []data.PublicKey) error {
|
||||||
for i := 0; i < len(ids); i++ {
|
for i := 0; i < len(ids); i++ {
|
||||||
privKey, _, err := r.CryptoService.GetPrivateKey(ids[i])
|
privKey, _, err := r.GetCryptoService().GetPrivateKey(ids[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not get the private key matching id %v: %v", ids[i], err)
|
return fmt.Errorf("could not get the private key matching id %v: %v", ids[i], err)
|
||||||
}
|
}
|
||||||
|
@ -317,7 +319,7 @@ func matchKeyIdsWithPubKeys(r *NotaryRepository, ids []string, pubKeys []data.Pu
|
||||||
// timestamp key and possibly other serverManagedRoles), but the created repository
|
// timestamp key and possibly other serverManagedRoles), but the created repository
|
||||||
// result is only stored on local disk, not published to the server. To do that,
|
// result is only stored on local disk, not published to the server. To do that,
|
||||||
// use r.Publish() eventually.
|
// use r.Publish() eventually.
|
||||||
func (r *NotaryRepository) Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error {
|
func (r *repository) Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error {
|
||||||
return r.initialize(rootKeyIDs, nil, serverManagedRoles...)
|
return r.initialize(rootKeyIDs, nil, serverManagedRoles...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,14 +343,14 @@ func keyExistsInList(cert data.PublicKey, ids map[string]bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeWithCertificate initializes the repository with root keys and their corresponding certificates
|
// InitializeWithCertificate initializes the repository with root keys and their corresponding certificates
|
||||||
func (r *NotaryRepository) InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey,
|
func (r *repository) InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey,
|
||||||
nRepo *NotaryRepository, serverManagedRoles ...data.RoleName) error {
|
serverManagedRoles ...data.RoleName) error {
|
||||||
|
|
||||||
// If we explicitly pass in certificate(s) but not key, then look keys up using certificate
|
// If we explicitly pass in certificate(s) but not key, then look keys up using certificate
|
||||||
if len(rootKeyIDs) == 0 && len(rootCerts) != 0 {
|
if len(rootKeyIDs) == 0 && len(rootCerts) != 0 {
|
||||||
rootKeyIDs = []string{}
|
rootKeyIDs = []string{}
|
||||||
availableRootKeyIDs := make(map[string]bool)
|
availableRootKeyIDs := make(map[string]bool)
|
||||||
for _, k := range nRepo.CryptoService.ListKeys(data.CanonicalRootRole) {
|
for _, k := range r.GetCryptoService().ListKeys(data.CanonicalRootRole) {
|
||||||
availableRootKeyIDs[k] = true
|
availableRootKeyIDs[k] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +365,7 @@ func (r *NotaryRepository) InitializeWithCertificate(rootKeyIDs []string, rootCe
|
||||||
return r.initialize(rootKeyIDs, rootCerts, serverManagedRoles...)
|
return r.initialize(rootKeyIDs, rootCerts, serverManagedRoles...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *NotaryRepository) initializeRoles(rootKeys []data.PublicKey, localRoles, remoteRoles []data.RoleName) (
|
func (r *repository) initializeRoles(rootKeys []data.PublicKey, localRoles, remoteRoles []data.RoleName) (
|
||||||
root, targets, snapshot, timestamp data.BaseRole, err error) {
|
root, targets, snapshot, timestamp data.BaseRole, err error) {
|
||||||
root = data.NewBaseRole(
|
root = data.NewBaseRole(
|
||||||
data.CanonicalRootRole,
|
data.CanonicalRootRole,
|
||||||
|
@ -376,7 +378,7 @@ func (r *NotaryRepository) initializeRoles(rootKeys []data.PublicKey, localRoles
|
||||||
for _, role := range localRoles {
|
for _, role := range localRoles {
|
||||||
// This is currently hardcoding the keys to ECDSA.
|
// This is currently hardcoding the keys to ECDSA.
|
||||||
var key data.PublicKey
|
var key data.PublicKey
|
||||||
key, err = r.CryptoService.Create(role, r.gun, data.ECDSAKey)
|
key, err = r.GetCryptoService().Create(role, r.gun, data.ECDSAKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -462,7 +464,7 @@ func addChange(cl changelist.Changelist, c changelist.Change, roles ...data.Role
|
||||||
// AddTarget creates new changelist entries to add a target to the given roles
|
// AddTarget creates new changelist entries to add a target to the given roles
|
||||||
// in the repository when the changelist gets applied at publish time.
|
// in the repository when the changelist gets applied at publish time.
|
||||||
// If roles are unspecified, the default role is "targets"
|
// If roles are unspecified, the default role is "targets"
|
||||||
func (r *NotaryRepository) AddTarget(target *Target, roles ...data.RoleName) error {
|
func (r *repository) AddTarget(target *Target, roles ...data.RoleName) error {
|
||||||
if len(target.Hashes) == 0 {
|
if len(target.Hashes) == 0 {
|
||||||
return fmt.Errorf("no hashes specified for target \"%s\"", target.Name)
|
return fmt.Errorf("no hashes specified for target \"%s\"", target.Name)
|
||||||
}
|
}
|
||||||
|
@ -483,7 +485,7 @@ func (r *NotaryRepository) AddTarget(target *Target, roles ...data.RoleName) err
|
||||||
// RemoveTarget creates new changelist entries to remove a target from the given
|
// RemoveTarget creates new changelist entries to remove a target from the given
|
||||||
// roles in the repository when the changelist gets applied at publish time.
|
// roles in the repository when the changelist gets applied at publish time.
|
||||||
// If roles are unspecified, the default role is "target".
|
// If roles are unspecified, the default role is "target".
|
||||||
func (r *NotaryRepository) RemoveTarget(targetName string, roles ...data.RoleName) error {
|
func (r *repository) RemoveTarget(targetName string, roles ...data.RoleName) error {
|
||||||
logrus.Debugf("Removing target \"%s\"", targetName)
|
logrus.Debugf("Removing target \"%s\"", targetName)
|
||||||
template := changelist.NewTUFChange(changelist.ActionDelete, "",
|
template := changelist.NewTUFChange(changelist.ActionDelete, "",
|
||||||
changelist.TypeTargetsTarget, targetName, nil)
|
changelist.TypeTargetsTarget, targetName, nil)
|
||||||
|
@ -498,7 +500,7 @@ func (r *NotaryRepository) RemoveTarget(targetName string, roles ...data.RoleNam
|
||||||
// its entries will be strictly shadowed by those in other parts of the "targets/a"
|
// its entries will be strictly shadowed by those in other parts of the "targets/a"
|
||||||
// subtree and also the "targets/x" subtree, as we will defer parsing it until
|
// subtree and also the "targets/x" subtree, as we will defer parsing it until
|
||||||
// we explicitly reach it in our iteration of the provided list of roles.
|
// we explicitly reach it in our iteration of the provided list of roles.
|
||||||
func (r *NotaryRepository) ListTargets(roles ...data.RoleName) ([]*TargetWithRole, error) {
|
func (r *repository) ListTargets(roles ...data.RoleName) ([]*TargetWithRole, error) {
|
||||||
if err := r.Update(false); err != nil {
|
if err := r.Update(false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -551,7 +553,7 @@ func (r *NotaryRepository) ListTargets(roles ...data.RoleName) ([]*TargetWithRol
|
||||||
// the target entry found in the subtree of the highest priority role
|
// the target entry found in the subtree of the highest priority role
|
||||||
// will be returned.
|
// will be returned.
|
||||||
// See the IMPORTANT section on ListTargets above. Those roles also apply here.
|
// See the IMPORTANT section on ListTargets above. Those roles also apply here.
|
||||||
func (r *NotaryRepository) GetTargetByName(name string, roles ...data.RoleName) (*TargetWithRole, error) {
|
func (r *repository) GetTargetByName(name string, roles ...data.RoleName) (*TargetWithRole, error) {
|
||||||
if err := r.Update(false); err != nil {
|
if err := r.Update(false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -605,7 +607,7 @@ func (f ErrNoSuchTarget) Error() string {
|
||||||
// GetAllTargetMetadataByName searches the entire delegation role tree to find the specified target by name for all
|
// GetAllTargetMetadataByName searches the entire delegation role tree to find the specified target by name for all
|
||||||
// roles, and returns a list of TargetSignedStructs for each time it finds the specified target.
|
// roles, and returns a list of TargetSignedStructs for each time it finds the specified target.
|
||||||
// If given an empty string for a target name, it will return back all targets signed into the repository in every role
|
// If given an empty string for a target name, it will return back all targets signed into the repository in every role
|
||||||
func (r *NotaryRepository) GetAllTargetMetadataByName(name string) ([]TargetSignedStruct, error) {
|
func (r *repository) GetAllTargetMetadataByName(name string) ([]TargetSignedStruct, error) {
|
||||||
if err := r.Update(false); err != nil {
|
if err := r.Update(false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -652,13 +654,13 @@ func (r *NotaryRepository) GetAllTargetMetadataByName(name string) ([]TargetSign
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChangelist returns the list of the repository's unpublished changes
|
// GetChangelist returns the list of the repository's unpublished changes
|
||||||
func (r *NotaryRepository) GetChangelist() (changelist.Changelist, error) {
|
func (r *repository) GetChangelist() (changelist.Changelist, error) {
|
||||||
return r.changelist, nil
|
return r.changelist, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRemoteStore returns the remoteStore of a repository if valid or
|
// getRemoteStore returns the remoteStore of a repository if valid or
|
||||||
// or an OfflineStore otherwise
|
// or an OfflineStore otherwise
|
||||||
func (r *NotaryRepository) getRemoteStore() store.RemoteStore {
|
func (r *repository) getRemoteStore() store.RemoteStore {
|
||||||
if r.remoteStore != nil {
|
if r.remoteStore != nil {
|
||||||
return r.remoteStore
|
return r.remoteStore
|
||||||
}
|
}
|
||||||
|
@ -676,7 +678,7 @@ type RoleWithSignatures struct {
|
||||||
|
|
||||||
// ListRoles returns a list of RoleWithSignatures objects for this repo
|
// ListRoles returns a list of RoleWithSignatures objects for this repo
|
||||||
// This represents the latest metadata for each role in this repo
|
// This represents the latest metadata for each role in this repo
|
||||||
func (r *NotaryRepository) ListRoles() ([]RoleWithSignatures, error) {
|
func (r *repository) ListRoles() ([]RoleWithSignatures, error) {
|
||||||
// Update to latest repo state
|
// Update to latest repo state
|
||||||
if err := r.Update(false); err != nil {
|
if err := r.Update(false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -715,7 +717,7 @@ func (r *NotaryRepository) ListRoles() ([]RoleWithSignatures, error) {
|
||||||
|
|
||||||
// Publish pushes the local changes in signed material to the remote notary-server
|
// Publish pushes the local changes in signed material to the remote notary-server
|
||||||
// Conceptually it performs an operation similar to a `git rebase`
|
// Conceptually it performs an operation similar to a `git rebase`
|
||||||
func (r *NotaryRepository) Publish() error {
|
func (r *repository) Publish() error {
|
||||||
if err := r.publish(r.changelist); err != nil {
|
if err := r.publish(r.changelist); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -730,7 +732,7 @@ func (r *NotaryRepository) Publish() error {
|
||||||
|
|
||||||
// publish pushes the changes in the given changelist to the remote notary-server
|
// publish pushes the changes in the given changelist to the remote notary-server
|
||||||
// Conceptually it performs an operation similar to a `git rebase`
|
// Conceptually it performs an operation similar to a `git rebase`
|
||||||
func (r *NotaryRepository) publish(cl changelist.Changelist) error {
|
func (r *repository) publish(cl changelist.Changelist) error {
|
||||||
var initialPublish bool
|
var initialPublish bool
|
||||||
// update first before publishing
|
// update first before publishing
|
||||||
if err := r.Update(true); err != nil {
|
if err := r.Update(true); err != nil {
|
||||||
|
@ -837,7 +839,7 @@ func signRootIfNecessary(updates map[data.RoleName][]byte, repo *tuf.Repo, extra
|
||||||
|
|
||||||
// Fetch back a `legacyVersions` number of roots files, collect the root public keys
|
// Fetch back a `legacyVersions` number of roots files, collect the root public keys
|
||||||
// This includes old `root` roles as well as legacy versioned root roles, e.g. `1.root`
|
// This includes old `root` roles as well as legacy versioned root roles, e.g. `1.root`
|
||||||
func (r *NotaryRepository) oldKeysForLegacyClientSupport(legacyVersions int, initialPublish bool) (data.KeyList, error) {
|
func (r *repository) oldKeysForLegacyClientSupport(legacyVersions int, initialPublish bool) (data.KeyList, error) {
|
||||||
if initialPublish {
|
if initialPublish {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -927,8 +929,8 @@ func signTargets(updates map[data.RoleName][]byte, repo *tuf.Repo, initialPublis
|
||||||
// r.tufRepo. This attempts to load metadata for all roles. Since server
|
// r.tufRepo. This attempts to load metadata for all roles. Since server
|
||||||
// snapshots are supported, if the snapshot metadata fails to load, that's ok.
|
// snapshots are supported, if the snapshot metadata fails to load, that's ok.
|
||||||
// This assumes that bootstrapRepo is only used by Publish() or RotateKey()
|
// This assumes that bootstrapRepo is only used by Publish() or RotateKey()
|
||||||
func (r *NotaryRepository) bootstrapRepo() error {
|
func (r *repository) bootstrapRepo() error {
|
||||||
b := tuf.NewRepoBuilder(r.gun, r.CryptoService, r.trustPinning)
|
b := tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), r.trustPinning)
|
||||||
|
|
||||||
logrus.Debugf("Loading trusted collection.")
|
logrus.Debugf("Loading trusted collection.")
|
||||||
|
|
||||||
|
@ -958,7 +960,7 @@ func (r *NotaryRepository) bootstrapRepo() error {
|
||||||
|
|
||||||
// saveMetadata saves contents of r.tufRepo onto the local disk, creating
|
// saveMetadata saves contents of r.tufRepo onto the local disk, creating
|
||||||
// signatures as necessary, possibly prompting for passphrases.
|
// signatures as necessary, possibly prompting for passphrases.
|
||||||
func (r *NotaryRepository) saveMetadata(ignoreSnapshot bool) error {
|
func (r *repository) saveMetadata(ignoreSnapshot bool) error {
|
||||||
logrus.Debugf("Saving changes to Trusted Collection.")
|
logrus.Debugf("Saving changes to Trusted Collection.")
|
||||||
|
|
||||||
rootJSON, err := serializeCanonicalRole(r.tufRepo, data.CanonicalRootRole, nil)
|
rootJSON, err := serializeCanonicalRole(r.tufRepo, data.CanonicalRootRole, nil)
|
||||||
|
@ -1002,7 +1004,7 @@ func (r *NotaryRepository) saveMetadata(ignoreSnapshot bool) error {
|
||||||
|
|
||||||
// returns a properly constructed ErrRepositoryNotExist error based on this
|
// returns a properly constructed ErrRepositoryNotExist error based on this
|
||||||
// repo's information
|
// repo's information
|
||||||
func (r *NotaryRepository) errRepositoryNotExist() error {
|
func (r *repository) errRepositoryNotExist() error {
|
||||||
host := r.baseURL
|
host := r.baseURL
|
||||||
parsed, err := url.Parse(r.baseURL)
|
parsed, err := url.Parse(r.baseURL)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -1013,7 +1015,7 @@ func (r *NotaryRepository) errRepositoryNotExist() error {
|
||||||
|
|
||||||
// Update bootstraps a trust anchor (root.json) before updating all the
|
// Update bootstraps a trust anchor (root.json) before updating all the
|
||||||
// metadata from the repo.
|
// metadata from the repo.
|
||||||
func (r *NotaryRepository) Update(forWrite bool) error {
|
func (r *repository) Update(forWrite bool) error {
|
||||||
c, err := r.bootstrapClient(forWrite)
|
c, err := r.bootstrapClient(forWrite)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(store.ErrMetaNotFound); ok {
|
if _, ok := err.(store.ErrMetaNotFound); ok {
|
||||||
|
@ -1059,14 +1061,14 @@ func (r *NotaryRepository) Update(forWrite bool) error {
|
||||||
//
|
//
|
||||||
// Returns a TUFClient for the remote server, which may not be actually
|
// Returns a TUFClient for the remote server, which may not be actually
|
||||||
// operational (if the URL is invalid but a root.json is cached).
|
// operational (if the URL is invalid but a root.json is cached).
|
||||||
func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*TUFClient, error) {
|
func (r *repository) bootstrapClient(checkInitialized bool) (*tufClient, error) {
|
||||||
minVersion := 1
|
minVersion := 1
|
||||||
// the old root on disk should not be validated against any trust pinning configuration
|
// the old root on disk should not be validated against any trust pinning configuration
|
||||||
// because if we have an old root, it itself is the thing that pins trust
|
// because if we have an old root, it itself is the thing that pins trust
|
||||||
oldBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService, trustpinning.TrustPinConfig{})
|
oldBuilder := tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), trustpinning.TrustPinConfig{})
|
||||||
|
|
||||||
// by default, we want to use the trust pinning configuration on any new root that we download
|
// by default, we want to use the trust pinning configuration on any new root that we download
|
||||||
newBuilder := tuf.NewRepoBuilder(r.gun, r.CryptoService, r.trustPinning)
|
newBuilder := tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), r.trustPinning)
|
||||||
|
|
||||||
// Try to read root from cache first. We will trust this root until we detect a problem
|
// Try to read root from cache first. We will trust this root until we detect a problem
|
||||||
// during update which will cause us to download a new root and perform a rotation.
|
// during update which will cause us to download a new root and perform a rotation.
|
||||||
|
@ -1080,7 +1082,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*TUFClient, e
|
||||||
|
|
||||||
// again, the root on disk is the source of trust pinning, so use an empty trust
|
// again, the root on disk is the source of trust pinning, so use an empty trust
|
||||||
// pinning configuration
|
// pinning configuration
|
||||||
newBuilder = tuf.NewRepoBuilder(r.gun, r.CryptoService, trustpinning.TrustPinConfig{})
|
newBuilder = tuf.NewRepoBuilder(r.gun, r.GetCryptoService(), trustpinning.TrustPinConfig{})
|
||||||
|
|
||||||
if err := newBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, false); err != nil {
|
if err := newBuilder.Load(data.CanonicalRootRole, rootJSON, minVersion, false); err != nil {
|
||||||
// Ok, the old root is expired - we want to download a new one. But we want to use the
|
// Ok, the old root is expired - we want to download a new one. But we want to use the
|
||||||
|
@ -1126,7 +1128,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*TUFClient, e
|
||||||
return nil, ErrRepoNotInitialized{}
|
return nil, ErrRepoNotInitialized{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewTUFClient(oldBuilder, newBuilder, remote, r.cache), nil
|
return newTufClient(oldBuilder, newBuilder, remote, r.cache), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RotateKey removes all existing keys associated with the role. If no keys are
|
// RotateKey removes all existing keys associated with the role. If no keys are
|
||||||
|
@ -1134,7 +1136,7 @@ func (r *NotaryRepository) bootstrapClient(checkInitialized bool) (*TUFClient, e
|
||||||
// managing the key to the server. If key(s) are specified by keyList, then they are
|
// managing the key to the server. If key(s) are specified by keyList, then they are
|
||||||
// used for signing the role.
|
// used for signing the role.
|
||||||
// These changes are staged in a changelist until publish is called.
|
// These changes are staged in a changelist until publish is called.
|
||||||
func (r *NotaryRepository) RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error {
|
func (r *repository) RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error {
|
||||||
if err := checkRotationInput(role, serverManagesKey); err != nil {
|
if err := checkRotationInput(role, serverManagesKey); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1152,7 +1154,7 @@ func (r *NotaryRepository) RotateKey(role data.RoleName, serverManagesKey bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Given a set of new keys to rotate to and a set of keys to drop, returns the list of current keys to use
|
// Given a set of new keys to rotate to and a set of keys to drop, returns the list of current keys to use
|
||||||
func (r *NotaryRepository) pubKeyListForRotation(role data.RoleName, serverManaged bool, newKeys []string) (pubKeyList data.KeyList, err error) {
|
func (r *repository) pubKeyListForRotation(role data.RoleName, serverManaged bool, newKeys []string) (pubKeyList data.KeyList, err error) {
|
||||||
var pubKey data.PublicKey
|
var pubKey data.PublicKey
|
||||||
|
|
||||||
// If server manages the key being rotated, request a rotation and return the new key
|
// If server manages the key being rotated, request a rotation and return the new key
|
||||||
|
@ -1170,7 +1172,7 @@ func (r *NotaryRepository) pubKeyListForRotation(role data.RoleName, serverManag
|
||||||
// If no new keys are passed in, we generate one
|
// If no new keys are passed in, we generate one
|
||||||
if len(newKeys) == 0 {
|
if len(newKeys) == 0 {
|
||||||
pubKeyList = make(data.KeyList, 0, 1)
|
pubKeyList = make(data.KeyList, 0, 1)
|
||||||
pubKey, err = r.CryptoService.Create(role, r.gun, data.ECDSAKey)
|
pubKey, err = r.GetCryptoService().Create(role, r.gun, data.ECDSAKey)
|
||||||
pubKeyList = append(pubKeyList, pubKey)
|
pubKeyList = append(pubKeyList, pubKey)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1181,7 +1183,7 @@ func (r *NotaryRepository) pubKeyListForRotation(role data.RoleName, serverManag
|
||||||
if len(newKeys) > 0 {
|
if len(newKeys) > 0 {
|
||||||
pubKeyList = make(data.KeyList, 0, len(newKeys))
|
pubKeyList = make(data.KeyList, 0, len(newKeys))
|
||||||
for _, keyID := range newKeys {
|
for _, keyID := range newKeys {
|
||||||
pubKey = r.CryptoService.GetKey(keyID)
|
pubKey = r.GetCryptoService().GetKey(keyID)
|
||||||
if pubKey == nil {
|
if pubKey == nil {
|
||||||
return nil, fmt.Errorf("unable to find key: %s", keyID)
|
return nil, fmt.Errorf("unable to find key: %s", keyID)
|
||||||
}
|
}
|
||||||
|
@ -1197,14 +1199,14 @@ func (r *NotaryRepository) pubKeyListForRotation(role data.RoleName, serverManag
|
||||||
return pubKeyList, nil
|
return pubKeyList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *NotaryRepository) pubKeysToCerts(role data.RoleName, pubKeyList data.KeyList) (data.KeyList, error) {
|
func (r *repository) pubKeysToCerts(role data.RoleName, pubKeyList data.KeyList) (data.KeyList, error) {
|
||||||
// only generate certs for root keys
|
// only generate certs for root keys
|
||||||
if role != data.CanonicalRootRole {
|
if role != data.CanonicalRootRole {
|
||||||
return pubKeyList, nil
|
return pubKeyList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, pubKey := range pubKeyList {
|
for i, pubKey := range pubKeyList {
|
||||||
privKey, loadedRole, err := r.CryptoService.GetPrivateKey(pubKey.ID())
|
privKey, loadedRole, err := r.GetCryptoService().GetPrivateKey(pubKey.ID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1238,7 +1240,7 @@ func checkRotationInput(role data.RoleName, serverManaged bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *NotaryRepository) rootFileKeyChange(cl changelist.Changelist, role data.RoleName, action string, keyList []data.PublicKey) error {
|
func (r *repository) rootFileKeyChange(cl changelist.Changelist, role data.RoleName, action string, keyList []data.PublicKey) error {
|
||||||
meta := changelist.TUFRootData{
|
meta := changelist.TUFRootData{
|
||||||
RoleName: role,
|
RoleName: role,
|
||||||
Keys: keyList,
|
Keys: keyList,
|
||||||
|
@ -1266,7 +1268,7 @@ func DeleteTrustData(baseDir string, gun data.GUN, URL string, rt http.RoundTrip
|
||||||
if err := os.RemoveAll(localRepo); err != nil {
|
if err := os.RemoveAll(localRepo); err != nil {
|
||||||
return fmt.Errorf("error clearing TUF repo data: %v", err)
|
return fmt.Errorf("error clearing TUF repo data: %v", err)
|
||||||
}
|
}
|
||||||
// Note that this will require admin permission in this NotaryRepository's roundtripper
|
// Note that this will require admin permission for the gun in the roundtripper
|
||||||
if deleteRemote {
|
if deleteRemote {
|
||||||
remote, err := getRemoteStore(URL, gun, rt)
|
remote, err := getRemoteStore(URL, gun, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1279,3 +1281,9 @@ func DeleteTrustData(baseDir string, gun data.GUN, URL string, rt http.RoundTrip
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLegacyVersions allows the number of legacy versions of the root
|
||||||
|
// to be inspected for old signing keys to be configured.
|
||||||
|
func (r *repository) SetLegacyVersions(n int) {
|
||||||
|
r.LegacyVersions = n
|
||||||
|
}
|
||||||
|
|
|
@ -4,17 +4,17 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/client/changelist"
|
"github.com/docker/notary/client/changelist"
|
||||||
store "github.com/docker/notary/storage"
|
store "github.com/docker/notary/storage"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AddDelegation creates changelist entries to add provided delegation public keys and paths.
|
// AddDelegation creates changelist entries to add provided delegation public keys and paths.
|
||||||
// This method composes AddDelegationRoleAndKeys and AddDelegationPaths (each creates one changelist if called).
|
// This method composes AddDelegationRoleAndKeys and AddDelegationPaths (each creates one changelist if called).
|
||||||
func (r *NotaryRepository) AddDelegation(name data.RoleName, delegationKeys []data.PublicKey, paths []string) error {
|
func (r *repository) AddDelegation(name data.RoleName, delegationKeys []data.PublicKey, paths []string) error {
|
||||||
if len(delegationKeys) > 0 {
|
if len(delegationKeys) > 0 {
|
||||||
err := r.AddDelegationRoleAndKeys(name, delegationKeys)
|
err := r.AddDelegationRoleAndKeys(name, delegationKeys)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -33,7 +33,7 @@ func (r *NotaryRepository) AddDelegation(name data.RoleName, delegationKeys []da
|
||||||
// AddDelegationRoleAndKeys creates a changelist entry to add provided delegation public keys.
|
// AddDelegationRoleAndKeys creates a changelist entry to add provided delegation public keys.
|
||||||
// This method is the simplest way to create a new delegation, because the delegation must have at least
|
// This method is the simplest way to create a new delegation, because the delegation must have at least
|
||||||
// one key upon creation to be valid since we will reject the changelist while validating the threshold.
|
// one key upon creation to be valid since we will reject the changelist while validating the threshold.
|
||||||
func (r *NotaryRepository) AddDelegationRoleAndKeys(name data.RoleName, delegationKeys []data.PublicKey) error {
|
func (r *repository) AddDelegationRoleAndKeys(name data.RoleName, delegationKeys []data.PublicKey) error {
|
||||||
|
|
||||||
if !data.IsDelegation(name) {
|
if !data.IsDelegation(name) {
|
||||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||||
|
@ -57,7 +57,7 @@ func (r *NotaryRepository) AddDelegationRoleAndKeys(name data.RoleName, delegati
|
||||||
|
|
||||||
// AddDelegationPaths creates a changelist entry to add provided paths to an existing delegation.
|
// AddDelegationPaths creates a changelist entry to add provided paths to an existing delegation.
|
||||||
// This method cannot create a new delegation itself because the role must meet the key threshold upon creation.
|
// This method cannot create a new delegation itself because the role must meet the key threshold upon creation.
|
||||||
func (r *NotaryRepository) AddDelegationPaths(name data.RoleName, paths []string) error {
|
func (r *repository) AddDelegationPaths(name data.RoleName, paths []string) error {
|
||||||
|
|
||||||
if !data.IsDelegation(name) {
|
if !data.IsDelegation(name) {
|
||||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||||
|
@ -78,7 +78,7 @@ func (r *NotaryRepository) AddDelegationPaths(name data.RoleName, paths []string
|
||||||
|
|
||||||
// RemoveDelegationKeysAndPaths creates changelist entries to remove provided delegation key IDs and paths.
|
// RemoveDelegationKeysAndPaths creates changelist entries to remove provided delegation key IDs and paths.
|
||||||
// This method composes RemoveDelegationPaths and RemoveDelegationKeys (each creates one changelist if called).
|
// This method composes RemoveDelegationPaths and RemoveDelegationKeys (each creates one changelist if called).
|
||||||
func (r *NotaryRepository) RemoveDelegationKeysAndPaths(name data.RoleName, keyIDs, paths []string) error {
|
func (r *repository) RemoveDelegationKeysAndPaths(name data.RoleName, keyIDs, paths []string) error {
|
||||||
if len(paths) > 0 {
|
if len(paths) > 0 {
|
||||||
err := r.RemoveDelegationPaths(name, paths)
|
err := r.RemoveDelegationPaths(name, paths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -95,7 +95,7 @@ func (r *NotaryRepository) RemoveDelegationKeysAndPaths(name data.RoleName, keyI
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveDelegationRole creates a changelist to remove all paths and keys from a role, and delete the role in its entirety.
|
// RemoveDelegationRole creates a changelist to remove all paths and keys from a role, and delete the role in its entirety.
|
||||||
func (r *NotaryRepository) RemoveDelegationRole(name data.RoleName) error {
|
func (r *repository) RemoveDelegationRole(name data.RoleName) error {
|
||||||
|
|
||||||
if !data.IsDelegation(name) {
|
if !data.IsDelegation(name) {
|
||||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||||
|
@ -108,7 +108,7 @@ func (r *NotaryRepository) RemoveDelegationRole(name data.RoleName) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveDelegationPaths creates a changelist entry to remove provided paths from an existing delegation.
|
// RemoveDelegationPaths creates a changelist entry to remove provided paths from an existing delegation.
|
||||||
func (r *NotaryRepository) RemoveDelegationPaths(name data.RoleName, paths []string) error {
|
func (r *repository) RemoveDelegationPaths(name data.RoleName, paths []string) error {
|
||||||
|
|
||||||
if !data.IsDelegation(name) {
|
if !data.IsDelegation(name) {
|
||||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||||
|
@ -132,7 +132,7 @@ func (r *NotaryRepository) RemoveDelegationPaths(name data.RoleName, paths []str
|
||||||
// the role itself will be deleted in its entirety.
|
// the role itself will be deleted in its entirety.
|
||||||
// It can also delete a key from all delegations under a parent using a name
|
// It can also delete a key from all delegations under a parent using a name
|
||||||
// with a wildcard at the end.
|
// with a wildcard at the end.
|
||||||
func (r *NotaryRepository) RemoveDelegationKeys(name data.RoleName, keyIDs []string) error {
|
func (r *repository) RemoveDelegationKeys(name data.RoleName, keyIDs []string) error {
|
||||||
|
|
||||||
if !data.IsDelegation(name) && !data.IsWildDelegation(name) {
|
if !data.IsDelegation(name) && !data.IsWildDelegation(name) {
|
||||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||||
|
@ -152,7 +152,7 @@ func (r *NotaryRepository) RemoveDelegationKeys(name data.RoleName, keyIDs []str
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearDelegationPaths creates a changelist entry to remove all paths from an existing delegation.
|
// ClearDelegationPaths creates a changelist entry to remove all paths from an existing delegation.
|
||||||
func (r *NotaryRepository) ClearDelegationPaths(name data.RoleName) error {
|
func (r *repository) ClearDelegationPaths(name data.RoleName) error {
|
||||||
|
|
||||||
if !data.IsDelegation(name) {
|
if !data.IsDelegation(name) {
|
||||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||||
|
@ -203,7 +203,7 @@ func newDeleteDelegationChange(name data.RoleName, content []byte) *changelist.T
|
||||||
|
|
||||||
// GetDelegationRoles returns the keys and roles of the repository's delegations
|
// GetDelegationRoles returns the keys and roles of the repository's delegations
|
||||||
// Also converts key IDs to canonical key IDs to keep consistent with signing prompts
|
// Also converts key IDs to canonical key IDs to keep consistent with signing prompts
|
||||||
func (r *NotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
func (r *repository) GetDelegationRoles() ([]data.Role, error) {
|
||||||
// Update state of the repo to latest
|
// Update state of the repo to latest
|
||||||
if err := r.Update(false); err != nil {
|
if err := r.Update(false); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -2,6 +2,7 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,13 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary/client/changelist"
|
"github.com/docker/notary/client/changelist"
|
||||||
store "github.com/docker/notary/storage"
|
store "github.com/docker/notary/storage"
|
||||||
"github.com/docker/notary/tuf"
|
"github.com/docker/notary/tuf"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/signed"
|
"github.com/docker/notary/tuf/signed"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Use this to initialize remote HTTPStores from the config settings
|
// Use this to initialize remote HTTPStores from the config settings
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/docker/notary/client/changelist"
|
||||||
|
"github.com/docker/notary/tuf/data"
|
||||||
|
"github.com/docker/notary/tuf/signed"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Repository represents the set of options that must be supported over a TUF repo.
|
||||||
|
type Repository interface {
|
||||||
|
// General management operations
|
||||||
|
Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error
|
||||||
|
InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error
|
||||||
|
Publish() error
|
||||||
|
|
||||||
|
// Target Operations
|
||||||
|
AddTarget(target *Target, roles ...data.RoleName) error
|
||||||
|
RemoveTarget(targetName string, roles ...data.RoleName) error
|
||||||
|
ListTargets(roles ...data.RoleName) ([]*TargetWithRole, error)
|
||||||
|
GetTargetByName(name string, roles ...data.RoleName) (*TargetWithRole, error)
|
||||||
|
GetAllTargetMetadataByName(name string) ([]TargetSignedStruct, error)
|
||||||
|
|
||||||
|
// Changelist operations
|
||||||
|
GetChangelist() (changelist.Changelist, error)
|
||||||
|
|
||||||
|
// Role operations
|
||||||
|
ListRoles() ([]RoleWithSignatures, error)
|
||||||
|
GetDelegationRoles() ([]data.Role, error)
|
||||||
|
AddDelegation(name data.RoleName, delegationKeys []data.PublicKey, paths []string) error
|
||||||
|
AddDelegationRoleAndKeys(name data.RoleName, delegationKeys []data.PublicKey) error
|
||||||
|
AddDelegationPaths(name data.RoleName, paths []string) error
|
||||||
|
RemoveDelegationKeysAndPaths(name data.RoleName, keyIDs, paths []string) error
|
||||||
|
RemoveDelegationRole(name data.RoleName) error
|
||||||
|
RemoveDelegationPaths(name data.RoleName, paths []string) error
|
||||||
|
RemoveDelegationKeys(name data.RoleName, keyIDs []string) error
|
||||||
|
ClearDelegationPaths(name data.RoleName) error
|
||||||
|
|
||||||
|
// Witness and other re-signing operations
|
||||||
|
Witness(roles ...data.RoleName) ([]data.RoleName, error)
|
||||||
|
|
||||||
|
// Key Operations
|
||||||
|
RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error
|
||||||
|
|
||||||
|
GetCryptoService() signed.CryptoService
|
||||||
|
SetLegacyVersions(int)
|
||||||
|
GetGUN() data.GUN
|
||||||
|
}
|
|
@ -4,26 +4,26 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
store "github.com/docker/notary/storage"
|
store "github.com/docker/notary/storage"
|
||||||
"github.com/docker/notary/trustpinning"
|
"github.com/docker/notary/trustpinning"
|
||||||
"github.com/docker/notary/tuf"
|
"github.com/docker/notary/tuf"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/signed"
|
"github.com/docker/notary/tuf/signed"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TUFClient is a usability wrapper around a raw TUF repo
|
// tufClient is a usability wrapper around a raw TUF repo
|
||||||
type TUFClient struct {
|
type tufClient struct {
|
||||||
remote store.RemoteStore
|
remote store.RemoteStore
|
||||||
cache store.MetadataStore
|
cache store.MetadataStore
|
||||||
oldBuilder tuf.RepoBuilder
|
oldBuilder tuf.RepoBuilder
|
||||||
newBuilder tuf.RepoBuilder
|
newBuilder tuf.RepoBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTUFClient initialized a TUFClient with the given repo, remote source of content, and cache
|
// newTufClient initialized a tufClient with the given repo, remote source of content, and cache
|
||||||
func NewTUFClient(oldBuilder, newBuilder tuf.RepoBuilder, remote store.RemoteStore, cache store.MetadataStore) *TUFClient {
|
func newTufClient(oldBuilder, newBuilder tuf.RepoBuilder, remote store.RemoteStore, cache store.MetadataStore) *tufClient {
|
||||||
return &TUFClient{
|
return &tufClient{
|
||||||
oldBuilder: oldBuilder,
|
oldBuilder: oldBuilder,
|
||||||
newBuilder: newBuilder,
|
newBuilder: newBuilder,
|
||||||
remote: remote,
|
remote: remote,
|
||||||
|
@ -32,7 +32,7 @@ func NewTUFClient(oldBuilder, newBuilder tuf.RepoBuilder, remote store.RemoteSto
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update performs an update to the TUF repo as defined by the TUF spec
|
// Update performs an update to the TUF repo as defined by the TUF spec
|
||||||
func (c *TUFClient) Update() (*tuf.Repo, *tuf.Repo, error) {
|
func (c *tufClient) Update() (*tuf.Repo, *tuf.Repo, error) {
|
||||||
// 1. Get timestamp
|
// 1. Get timestamp
|
||||||
// a. If timestamp error (verification, expired, etc...) download new root and return to 1.
|
// a. If timestamp error (verification, expired, etc...) download new root and return to 1.
|
||||||
// 2. Check if local snapshot is up to date
|
// 2. Check if local snapshot is up to date
|
||||||
|
@ -63,7 +63,7 @@ func (c *TUFClient) Update() (*tuf.Repo, *tuf.Repo, error) {
|
||||||
return c.newBuilder.Finish()
|
return c.newBuilder.Finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TUFClient) update() error {
|
func (c *tufClient) update() error {
|
||||||
if err := c.downloadTimestamp(); err != nil {
|
if err := c.downloadTimestamp(); err != nil {
|
||||||
logrus.Debugf("Client Update (Timestamp): %s", err.Error())
|
logrus.Debugf("Client Update (Timestamp): %s", err.Error())
|
||||||
return err
|
return err
|
||||||
|
@ -82,7 +82,7 @@ func (c *TUFClient) update() error {
|
||||||
|
|
||||||
// updateRoot checks if there is a newer version of the root available, and if so
|
// updateRoot checks if there is a newer version of the root available, and if so
|
||||||
// downloads all intermediate root files to allow proper key rotation.
|
// downloads all intermediate root files to allow proper key rotation.
|
||||||
func (c *TUFClient) updateRoot() error {
|
func (c *tufClient) updateRoot() error {
|
||||||
// Get current root version
|
// Get current root version
|
||||||
currentRootConsistentInfo := c.oldBuilder.GetConsistentInfo(data.CanonicalRootRole)
|
currentRootConsistentInfo := c.oldBuilder.GetConsistentInfo(data.CanonicalRootRole)
|
||||||
currentVersion := c.oldBuilder.GetLoadedVersion(currentRootConsistentInfo.RoleName)
|
currentVersion := c.oldBuilder.GetLoadedVersion(currentRootConsistentInfo.RoleName)
|
||||||
|
@ -147,7 +147,7 @@ func (c *TUFClient) updateRoot() error {
|
||||||
|
|
||||||
// updateRootVersions updates the root from it's current version to a target, rotating keys
|
// updateRootVersions updates the root from it's current version to a target, rotating keys
|
||||||
// as they are found
|
// as they are found
|
||||||
func (c *TUFClient) updateRootVersions(fromVersion, toVersion int) error {
|
func (c *tufClient) updateRootVersions(fromVersion, toVersion int) error {
|
||||||
for v := fromVersion; v <= toVersion; v++ {
|
for v := fromVersion; v <= toVersion; v++ {
|
||||||
logrus.Debugf("updating root from version %d to version %d, currently fetching %d", fromVersion, toVersion, v)
|
logrus.Debugf("updating root from version %d to version %d, currently fetching %d", fromVersion, toVersion, v)
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ func (c *TUFClient) updateRootVersions(fromVersion, toVersion int) error {
|
||||||
// downloadTimestamp is responsible for downloading the timestamp.json
|
// downloadTimestamp is responsible for downloading the timestamp.json
|
||||||
// Timestamps are special in that we ALWAYS attempt to download and only
|
// Timestamps are special in that we ALWAYS attempt to download and only
|
||||||
// use cache if the download fails (and the cache is still valid).
|
// use cache if the download fails (and the cache is still valid).
|
||||||
func (c *TUFClient) downloadTimestamp() error {
|
func (c *tufClient) downloadTimestamp() error {
|
||||||
logrus.Debug("Loading timestamp...")
|
logrus.Debug("Loading timestamp...")
|
||||||
role := data.CanonicalTimestampRole
|
role := data.CanonicalTimestampRole
|
||||||
consistentInfo := c.newBuilder.GetConsistentInfo(role)
|
consistentInfo := c.newBuilder.GetConsistentInfo(role)
|
||||||
|
@ -206,7 +206,7 @@ func (c *TUFClient) downloadTimestamp() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadSnapshot is responsible for downloading the snapshot.json
|
// downloadSnapshot is responsible for downloading the snapshot.json
|
||||||
func (c *TUFClient) downloadSnapshot() error {
|
func (c *tufClient) downloadSnapshot() error {
|
||||||
logrus.Debug("Loading snapshot...")
|
logrus.Debug("Loading snapshot...")
|
||||||
role := data.CanonicalSnapshotRole
|
role := data.CanonicalSnapshotRole
|
||||||
consistentInfo := c.newBuilder.GetConsistentInfo(role)
|
consistentInfo := c.newBuilder.GetConsistentInfo(role)
|
||||||
|
@ -218,7 +218,7 @@ func (c *TUFClient) downloadSnapshot() error {
|
||||||
// downloadTargets downloads all targets and delegated targets for the repository.
|
// downloadTargets downloads all targets and delegated targets for the repository.
|
||||||
// It uses a pre-order tree traversal as it's necessary to download parents first
|
// It uses a pre-order tree traversal as it's necessary to download parents first
|
||||||
// to obtain the keys to validate children.
|
// to obtain the keys to validate children.
|
||||||
func (c *TUFClient) downloadTargets() error {
|
func (c *tufClient) downloadTargets() error {
|
||||||
toDownload := []data.DelegationRole{{
|
toDownload := []data.DelegationRole{{
|
||||||
BaseRole: data.BaseRole{Name: data.CanonicalTargetsRole},
|
BaseRole: data.BaseRole{Name: data.CanonicalTargetsRole},
|
||||||
Paths: []string{""},
|
Paths: []string{""},
|
||||||
|
@ -251,7 +251,7 @@ func (c *TUFClient) downloadTargets() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c TUFClient) getTargetsFile(role data.DelegationRole, ci tuf.ConsistentInfo) ([]data.DelegationRole, error) {
|
func (c tufClient) getTargetsFile(role data.DelegationRole, ci tuf.ConsistentInfo) ([]data.DelegationRole, error) {
|
||||||
logrus.Debugf("Loading %s...", role.Name)
|
logrus.Debugf("Loading %s...", role.Name)
|
||||||
tgs := &data.SignedTargets{}
|
tgs := &data.SignedTargets{}
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ func (c TUFClient) getTargetsFile(role data.DelegationRole, ci tuf.ConsistentInf
|
||||||
}
|
}
|
||||||
|
|
||||||
// downloadRoot is responsible for downloading the root.json
|
// downloadRoot is responsible for downloading the root.json
|
||||||
func (c *TUFClient) downloadRoot() ([]byte, error) {
|
func (c *tufClient) downloadRoot() ([]byte, error) {
|
||||||
role := data.CanonicalRootRole
|
role := data.CanonicalRootRole
|
||||||
consistentInfo := c.newBuilder.GetConsistentInfo(role)
|
consistentInfo := c.newBuilder.GetConsistentInfo(role)
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ func (c *TUFClient) downloadRoot() ([]byte, error) {
|
||||||
return c.tryLoadCacheThenRemote(consistentInfo)
|
return c.tryLoadCacheThenRemote(consistentInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TUFClient) tryLoadCacheThenRemote(consistentInfo tuf.ConsistentInfo) ([]byte, error) {
|
func (c *tufClient) tryLoadCacheThenRemote(consistentInfo tuf.ConsistentInfo) ([]byte, error) {
|
||||||
cachedTS, err := c.cache.GetSized(consistentInfo.RoleName.String(), consistentInfo.Length())
|
cachedTS, err := c.cache.GetSized(consistentInfo.RoleName.String(), consistentInfo.Length())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Debugf("no %s in cache, must download", consistentInfo.RoleName)
|
logrus.Debugf("no %s in cache, must download", consistentInfo.RoleName)
|
||||||
|
@ -300,7 +300,7 @@ func (c *TUFClient) tryLoadCacheThenRemote(consistentInfo tuf.ConsistentInfo) ([
|
||||||
return c.tryLoadRemote(consistentInfo, cachedTS)
|
return c.tryLoadRemote(consistentInfo, cachedTS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TUFClient) tryLoadRemote(consistentInfo tuf.ConsistentInfo, old []byte) ([]byte, error) {
|
func (c *tufClient) tryLoadRemote(consistentInfo tuf.ConsistentInfo, old []byte) ([]byte, error) {
|
||||||
consistentName := consistentInfo.ConsistentName()
|
consistentName := consistentInfo.ConsistentName()
|
||||||
raw, err := c.remote.GetSized(consistentName, consistentInfo.Length())
|
raw, err := c.remote.GetSized(consistentName, consistentInfo.Length())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
// Witness creates change objects to witness (i.e. re-sign) the given
|
// Witness creates change objects to witness (i.e. re-sign) the given
|
||||||
// roles on the next publish. One change is created per role
|
// roles on the next publish. One change is created per role
|
||||||
func (r *NotaryRepository) Witness(roles ...data.RoleName) ([]data.RoleName, error) {
|
func (r *repository) Witness(roles ...data.RoleName) ([]data.RoleName, error) {
|
||||||
var err error
|
var err error
|
||||||
successful := make([]data.RoleName, 0, len(roles))
|
successful := make([]data.RoleName, 0, len(roles))
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
|
|
|
@ -6,11 +6,11 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/trustmanager"
|
"github.com/docker/notary/trustmanager"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -36,6 +36,10 @@ func NewCryptoService(keyStores ...trustmanager.KeyStore) *CryptoService {
|
||||||
|
|
||||||
// Create is used to generate keys for targets, snapshots and timestamps
|
// Create is used to generate keys for targets, snapshots and timestamps
|
||||||
func (cs *CryptoService) Create(role data.RoleName, gun data.GUN, algorithm string) (data.PublicKey, error) {
|
func (cs *CryptoService) Create(role data.RoleName, gun data.GUN, algorithm string) (data.PublicKey, error) {
|
||||||
|
if algorithm == data.RSAKey {
|
||||||
|
return nil, fmt.Errorf("%s keys can only be imported", data.RSAKey)
|
||||||
|
}
|
||||||
|
|
||||||
privKey, err := utils.GenerateKey(algorithm)
|
privKey, err := utils.GenerateKey(algorithm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate %s key: %v", algorithm, err)
|
return nil, fmt.Errorf("failed to generate %s key: %v", algorithm, err)
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewFileStore creates a fully configurable file store
|
// NewFileStore creates a fully configurable file store
|
||||||
|
@ -63,7 +63,7 @@ func (f *FilesystemStore) moveKeyTo0Dot4Location(file string) {
|
||||||
fileDir = strings.TrimPrefix(fileDir, notary.RootKeysSubdir)
|
fileDir = strings.TrimPrefix(fileDir, notary.RootKeysSubdir)
|
||||||
fileDir = strings.TrimPrefix(fileDir, notary.NonRootKeysSubdir)
|
fileDir = strings.TrimPrefix(fileDir, notary.NonRootKeysSubdir)
|
||||||
if fileDir != "" {
|
if fileDir != "" {
|
||||||
block.Headers["gun"] = fileDir[1:]
|
block.Headers["gun"] = filepath.ToSlash(fileDir[1:])
|
||||||
}
|
}
|
||||||
if strings.Contains(keyID, "_") {
|
if strings.Contains(keyID, "_") {
|
||||||
role := strings.Split(keyID, "_")[1]
|
role := strings.Split(keyID, "_")[1]
|
||||||
|
|
|
@ -22,10 +22,10 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/validation"
|
"github.com/docker/notary/tuf/validation"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -6,11 +6,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
store "github.com/docker/notary/storage"
|
store "github.com/docker/notary/storage"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type keyInfoMap map[string]KeyInfo
|
type keyInfoMap map[string]KeyInfo
|
||||||
|
|
|
@ -5,6 +5,7 @@ package yubikey
|
||||||
import (
|
import (
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/trustmanager"
|
"github.com/docker/notary/trustmanager"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
|
|
|
@ -16,13 +16,13 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/trustmanager"
|
"github.com/docker/notary/trustmanager"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/signed"
|
"github.com/docker/notary/tuf/signed"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
"github.com/miekg/pkcs11"
|
"github.com/miekg/pkcs11"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -6,10 +6,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/signed"
|
"github.com/docker/notary/tuf/signed"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const wildcard = "*"
|
const wildcard = "*"
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TrustPinConfig represents the configuration under the trust_pinning section of the config file
|
// TrustPinConfig represents the configuration under the trust_pinning section of the config file
|
||||||
|
|
|
@ -12,9 +12,9 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/agl/ed25519"
|
"github.com/agl/ed25519"
|
||||||
"github.com/docker/go/canonical/json"
|
"github.com/docker/go/canonical/json"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PublicKey is the necessary interface for public keys
|
// PublicKey is the necessary interface for public keys
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Canonical base role names
|
// Canonical base role names
|
||||||
|
|
|
@ -4,9 +4,9 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/go/canonical/json"
|
"github.com/docker/go/canonical/json"
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignedSnapshot is a fully unpacked snapshot.json
|
// SignedSnapshot is a fully unpacked snapshot.json
|
||||||
|
|
|
@ -14,9 +14,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/go/canonical/json"
|
"github.com/docker/go/canonical/json"
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GUN type for specifying gun
|
// GUN type for specifying gun
|
||||||
|
|
|
@ -14,10 +14,10 @@ package signed
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary/trustmanager"
|
"github.com/docker/notary/trustmanager"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sign takes a data.Signed and a cryptoservice containing private keys,
|
// Sign takes a data.Signed and a cryptoservice containing private keys,
|
||||||
|
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/agl/ed25519"
|
"github.com/agl/ed25519"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -6,10 +6,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/go/canonical/json"
|
"github.com/docker/go/canonical/json"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Various basic signing errors
|
// Various basic signing errors
|
||||||
|
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
"github.com/docker/notary/tuf/signed"
|
"github.com/docker/notary/tuf/signed"
|
||||||
"github.com/docker/notary/tuf/utils"
|
"github.com/docker/notary/tuf/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrSigVerifyFail - signature verification failed
|
// ErrSigVerifyFail - signature verification failed
|
||||||
|
|
|
@ -16,10 +16,10 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/agl/ed25519"
|
"github.com/agl/ed25519"
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CanonicalKeyID returns the ID of the public bytes version of a TUF key.
|
// CanonicalKeyID returns the ID of the public bytes version of a TUF key.
|
||||||
|
@ -339,8 +339,6 @@ func ValidateCertificate(c *x509.Certificate, checkExpiry bool) error {
|
||||||
// error detailing why the key could not be generated
|
// error detailing why the key could not be generated
|
||||||
func GenerateKey(algorithm string) (data.PrivateKey, error) {
|
func GenerateKey(algorithm string) (data.PrivateKey, error) {
|
||||||
switch algorithm {
|
switch algorithm {
|
||||||
case data.RSAKey:
|
|
||||||
return GenerateRSAKey(rand.Reader, notary.MinRSABitSize)
|
|
||||||
case data.ECDSAKey:
|
case data.ECDSAKey:
|
||||||
return GenerateECDSAKey(rand.Reader)
|
return GenerateECDSAKey(rand.Reader)
|
||||||
case data.ED25519Key:
|
case data.ED25519Key:
|
||||||
|
@ -349,23 +347,6 @@ func GenerateKey(algorithm string) (data.PrivateKey, error) {
|
||||||
return nil, fmt.Errorf("private key type not supported for key generation: %s", algorithm)
|
return nil, fmt.Errorf("private key type not supported for key generation: %s", algorithm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not generate private key: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tufPrivKey, err := RSAToPrivateKey(rsaPrivKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Debugf("generated RSA key with keyID: %s", tufPrivKey.ID())
|
|
||||||
|
|
||||||
return tufPrivKey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RSAToPrivateKey converts an rsa.Private key to a TUF data.PrivateKey type
|
// RSAToPrivateKey converts an rsa.Private key to a TUF data.PrivateKey type
|
||||||
func RSAToPrivateKey(rsaPrivKey *rsa.PrivateKey) (data.PrivateKey, error) {
|
func RSAToPrivateKey(rsaPrivKey *rsa.PrivateKey) (data.PrivateKey, error) {
|
||||||
// Get a DER-encoded representation of the PublicKey
|
// Get a DER-encoded representation of the PublicKey
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
github.com/Shopify/logrus-bugsnag 5a46080c635f13e8b60c24765c19d62e1ca8d0fb
|
github.com/Shopify/logrus-bugsnag 6dbc35f2c30d1e37549f9673dd07912452ab28a5
|
||||||
github.com/Sirupsen/logrus 6d9ae300aaf85d6acd2e5424081c7fcddb21dab8
|
github.com/sirupsen/logrus f006c2ac4710855cf0f916dd6b77acf6b048dc6e # v1.0.3
|
||||||
github.com/agl/ed25519 278e1ec8e8a6e017cd07577924d6766039146ced
|
github.com/agl/ed25519 278e1ec8e8a6e017cd07577924d6766039146ced
|
||||||
github.com/bugsnag/bugsnag-go 13fd6b8acda029830ef9904df6b63be0a83369d0
|
github.com/bugsnag/bugsnag-go 13fd6b8acda029830ef9904df6b63be0a83369d0
|
||||||
github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782
|
github.com/bugsnag/panicwrap e2c28503fcd0675329da73bf48b33404db873782
|
||||||
github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702
|
github.com/bugsnag/osext 0dd3f918b21bec95ace9dc86c7e70266cfc5c702
|
||||||
github.com/docker/distribution 325b0804fef3a66309d962357aac3c2ce3f4d329 # v2.6.0
|
github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
|
||||||
github.com/docker/go-connections f549a9393d05688dff0992ef3efd8bbe6c628aeb
|
github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
|
||||||
|
github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
|
||||||
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
|
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06
|
||||||
github.com/dvsekhvalnov/jose2go 6387d3c1f5abd8443b223577d5a7e0f4e0e5731f # v1.2
|
github.com/dvsekhvalnov/jose2go 6387d3c1f5abd8443b223577d5a7e0f4e0e5731f # v1.2
|
||||||
github.com/go-sql-driver/mysql a0583e0143b1624142adab07e0e97fe106d99561 # v1.3
|
github.com/go-sql-driver/mysql a0583e0143b1624142adab07e0e97fe106d99561 # v1.3
|
||||||
|
@ -25,7 +26,9 @@ github.com/spf13/cobra f368244301305f414206f889b1735a54cfc8bde8
|
||||||
github.com/spf13/viper be5ff3e4840cf692388bde7a057595a474ef379e
|
github.com/spf13/viper be5ff3e4840cf692388bde7a057595a474ef379e
|
||||||
golang.org/x/crypto 5bcd134fee4dd1475da17714aac19c0aa0142e2f
|
golang.org/x/crypto 5bcd134fee4dd1475da17714aac19c0aa0142e2f
|
||||||
golang.org/x/net 6a513affb38dc9788b449d59ffed099b8de18fa0
|
golang.org/x/net 6a513affb38dc9788b449d59ffed099b8de18fa0
|
||||||
|
golang.org/x/sys 739734461d1c916b6c72a63d7efda2b27edb369f
|
||||||
google.golang.org/grpc 708a7f9f3283aa2d4f6132d287d78683babe55c8 # v1.0.5
|
google.golang.org/grpc 708a7f9f3283aa2d4f6132d287d78683babe55c8 # v1.0.5
|
||||||
|
github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
|
||||||
|
|
||||||
github.com/spf13/pflag cb88ea77998c3f024757528e3305022ab50b43be
|
github.com/spf13/pflag cb88ea77998c3f024757528e3305022ab50b43be
|
||||||
github.com/spf13/cast 4d07383ffe94b5e5a6fa3af9211374a4507a0184
|
github.com/spf13/cast 4d07383ffe94b5e5a6fa3af9211374a4507a0184
|
||||||
|
@ -40,14 +43,14 @@ github.com/kr/pretty bc9499caa0f45ee5edb2f0209fbd61fbf3d9018f # go.weekly.
|
||||||
github.com/hailocab/go-hostpool e80d13ce29ede4452c43dea11e79b9bc8a15b478
|
github.com/hailocab/go-hostpool e80d13ce29ede4452c43dea11e79b9bc8a15b478
|
||||||
github.com/docker/libtrust aabc10ec26b754e797f9028f4589c5b7bd90dc20
|
github.com/docker/libtrust aabc10ec26b754e797f9028f4589c5b7bd90dc20
|
||||||
github.com/beorn7/perks b965b613227fddccbfffe13eae360ed3fa822f8d
|
github.com/beorn7/perks b965b613227fddccbfffe13eae360ed3fa822f8d
|
||||||
github.com/BurntSushi/toml bd2bdf7f18f849530ef7a1c29a4290217cab32a1
|
github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
|
||||||
|
|
||||||
github.com/matttproud/golang_protobuf_extensions d0c3fe89de86839aecf2e0579c40ba3bb336a453
|
github.com/matttproud/golang_protobuf_extensions d0c3fe89de86839aecf2e0579c40ba3bb336a453
|
||||||
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||||
|
|
||||||
gopkg.in/dancannon/gorethink.v3 417badecf1ab14d0d6e38ad82397da2a59e2f6ca # v3.0.0
|
gopkg.in/dancannon/gorethink.v3 e324d6ad938205da6c1e8a0179dc97a5b1a92185 https://github.com/docker/gorethink # v3.0.0-logrus
|
||||||
# dependencies of gorethink.v3
|
# dependencies of gorethink.v3
|
||||||
gopkg.in/gorethink/gorethink.v2 016a1d3b4d15951ab2e39bd3596718ba94d298ba # v2.2.2
|
gopkg.in/gorethink/gorethink.v2 ac5be4ae8538d44ae8843b97fc9f90860cb48a85 https://github.com/docker/gorethink # v2.2.2-logrus
|
||||||
github.com/cenk/backoff 32cd0c5b3aef12c76ed64aaf678f6c79736be7dc # v1.0.0
|
github.com/cenk/backoff 32cd0c5b3aef12c76ed64aaf678f6c79736be7dc # v1.0.0
|
||||||
|
|
||||||
# Testing requirements
|
# Testing requirements
|
||||||
|
|
Loading…
Reference in New Issue