mirror of https://github.com/docker/cli.git
trust: update existing code for new vendoring, refactor for docker trust code sharing
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
parent
fb1cbaeb66
commit
5846e6e5d5
|
@ -48,7 +48,7 @@ func runPush(dockerCli command.Cli, remote string) error {
|
||||||
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")
|
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "push")
|
||||||
|
|
||||||
if command.IsTrusted() {
|
if command.IsTrusted() {
|
||||||
return trustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege)
|
return TrustedPush(ctx, dockerCli, repoInfo, ref, authConfig, requestPrivilege)
|
||||||
}
|
}
|
||||||
|
|
||||||
responseBody, err := imagePushPrivileged(ctx, dockerCli, authConfig, ref, requestPrivilege)
|
responseBody, err := imagePushPrivileged(ctx, dockerCli, authConfig, ref, requestPrivilege)
|
||||||
|
|
|
@ -28,8 +28,8 @@ type target struct {
|
||||||
size int64
|
size int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// trustedPush handles content trust pushing of an image
|
// TrustedPush handles content trust pushing of an image
|
||||||
func trustedPush(ctx context.Context, cli command.Cli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
|
func TrustedPush(ctx context.Context, cli command.Cli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error {
|
||||||
responseBody, err := imagePushPrivileged(ctx, cli, authConfig, ref, requestPrivilege)
|
responseBody, err := imagePushPrivileged(ctx, cli, authConfig, ref, requestPrivilege)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -136,7 +136,7 @@ func PushTrustedReference(streams command.Streams, repoInfo *registry.Repository
|
||||||
err = repo.AddTarget(target, data.CanonicalTargetsRole)
|
err = repo.AddTarget(target, data.CanonicalTargetsRole)
|
||||||
case nil:
|
case nil:
|
||||||
// already initialized and we have successfully downloaded the latest metadata
|
// already initialized and we have successfully downloaded the latest metadata
|
||||||
err = addTargetToAllSignableRoles(repo, target)
|
err = AddTargetToAllSignableRoles(repo, target)
|
||||||
default:
|
default:
|
||||||
return trust.NotaryError(repoInfo.Name.Name(), err)
|
return trust.NotaryError(repoInfo.Name.Name(), err)
|
||||||
}
|
}
|
||||||
|
@ -154,12 +154,10 @@ func PushTrustedReference(streams command.Streams, repoInfo *registry.Repository
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to add the image target to all the top level delegation roles we can
|
// GetSignableRoles returns a list of roles for which we have valid signing
|
||||||
// (based on whether we have the signing key and whether the role's path allows
|
// keys, given a notary repository and a target
|
||||||
// us to).
|
func GetSignableRoles(repo *client.NotaryRepository, target *client.Target) ([]data.RoleName, error) {
|
||||||
// If there are no delegation roles, we add to the targets role.
|
var signableRoles []data.RoleName
|
||||||
func addTargetToAllSignableRoles(repo *client.NotaryRepository, target *client.Target) error {
|
|
||||||
var signableRoles []string
|
|
||||||
|
|
||||||
// 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{})
|
||||||
|
@ -169,12 +167,13 @@ func addTargetToAllSignableRoles(repo *client.NotaryRepository, target *client.T
|
||||||
|
|
||||||
allDelegationRoles, err := repo.GetDelegationRoles()
|
allDelegationRoles, err := repo.GetDelegationRoles()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return signableRoles, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there are no delegation roles, then just try to sign it into the targets role
|
// if there are no delegation roles, then just try to sign it into the targets role
|
||||||
if len(allDelegationRoles) == 0 {
|
if len(allDelegationRoles) == 0 {
|
||||||
return repo.AddTarget(target, data.CanonicalTargetsRole)
|
signableRoles = append(signableRoles, data.CanonicalTargetsRole)
|
||||||
|
return signableRoles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// there are delegation roles, find every delegation role we have a key for, and
|
// there are delegation roles, find every delegation role we have a key for, and
|
||||||
|
@ -183,7 +182,7 @@ func addTargetToAllSignableRoles(repo *client.NotaryRepository, target *client.T
|
||||||
// We do not support signing any delegation role that isn't a direct child of the targets role.
|
// We do not support signing any delegation role that isn't a direct child of the targets role.
|
||||||
// Also don't bother checking the keys if we can't add the target
|
// Also don't bother checking the keys if we can't add the target
|
||||||
// to this role due to path restrictions
|
// to this role due to path restrictions
|
||||||
if path.Dir(delegationRole.Name) != data.CanonicalTargetsRole || !delegationRole.CheckPaths(target.Name) {
|
if path.Dir(delegationRole.Name.String()) != data.CanonicalTargetsRole.String() || !delegationRole.CheckPaths(target.Name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +195,21 @@ func addTargetToAllSignableRoles(repo *client.NotaryRepository, target *client.T
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(signableRoles) == 0 {
|
if len(signableRoles) == 0 {
|
||||||
return errors.Errorf("no valid signing keys for delegation roles")
|
return signableRoles, errors.Errorf("no valid signing keys for delegation roles")
|
||||||
|
}
|
||||||
|
|
||||||
|
return signableRoles, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddTargetToAllSignableRoles attempts to add the image target to all the top level delegation roles we can
|
||||||
|
// (based on whether we have the signing key and whether the role's path allows
|
||||||
|
// us to).
|
||||||
|
// If there are no delegation roles, we add to the targets role.
|
||||||
|
func AddTargetToAllSignableRoles(repo *client.NotaryRepository, target *client.Target) error {
|
||||||
|
signableRoles, err := GetSignableRoles(repo, target)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return repo.AddTarget(target, signableRoles...)
|
return repo.AddTarget(target, signableRoles...)
|
||||||
|
@ -348,7 +361,7 @@ func TrustedReference(ctx context.Context, cli command.Cli, ref reference.NamedT
|
||||||
// Only list tags in the top level targets role or the releases delegation role - ignore
|
// Only list tags in the top level targets role or the releases delegation role - ignore
|
||||||
// all other delegation roles
|
// all other delegation roles
|
||||||
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
|
if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
|
||||||
return nil, trust.NotaryError(repoInfo.Name.Name(), errors.Errorf("No trust data for %s", ref.Tag()))
|
return nil, trust.NotaryError(repoInfo.Name.Name(), client.ErrNoSuchTarget(ref.Tag()))
|
||||||
}
|
}
|
||||||
r, err := convertTarget(t.Target)
|
r, err := convertTarget(t.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
package image
|
package image
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/cli/cli/trust"
|
"github.com/docker/cli/cli/trust"
|
||||||
registrytypes "github.com/docker/docker/api/types/registry"
|
registrytypes "github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/registry"
|
"github.com/docker/docker/registry"
|
||||||
|
"github.com/docker/notary/client"
|
||||||
|
"github.com/docker/notary/passphrase"
|
||||||
|
"github.com/docker/notary/trustpinning"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func unsetENV() {
|
func unsetENV() {
|
||||||
|
@ -55,3 +60,25 @@ func TestNonOfficialTrustServer(t *testing.T) {
|
||||||
t.Fatalf("Expected server to be %s, got %s", expectedStr, output)
|
t.Fatalf("Expected server to be %s, got %s", expectedStr, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddTargetToAllSignableRolesError(t *testing.T) {
|
||||||
|
tmpDir, err := ioutil.TempDir("", "notary-test-")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
|
||||||
|
target := client.Target{}
|
||||||
|
err = AddTargetToAllSignableRoles(notaryRepo, &target)
|
||||||
|
assert.EqualError(t, err, "client is offline")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetSignableRolesError(t *testing.T) {
|
||||||
|
tmpDir, err := ioutil.TempDir("", "notary-test-")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
|
notaryRepo, err := client.NewFileCachedNotaryRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
|
||||||
|
target := client.Target{}
|
||||||
|
_, err = GetSignableRoles(notaryRepo, &target)
|
||||||
|
assert.EqualError(t, err, "client is offline")
|
||||||
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ReleasesRole is the role named "releases"
|
// ReleasesRole is the role named "releases"
|
||||||
ReleasesRole = path.Join(data.CanonicalTargetsRole, "releases")
|
ReleasesRole = data.RoleName(path.Join(data.CanonicalTargetsRole.String(), "releases"))
|
||||||
)
|
)
|
||||||
|
|
||||||
func trustDirectory() string {
|
func trustDirectory() string {
|
||||||
|
@ -164,9 +164,9 @@ 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.NewNotaryRepository(
|
return client.NewFileCachedNotaryRepository(
|
||||||
trustDirectory(),
|
trustDirectory(),
|
||||||
repoInfo.Name.Name(),
|
data.GUN(repoInfo.Name.Name()),
|
||||||
server,
|
server,
|
||||||
tr,
|
tr,
|
||||||
getPassphraseRetriever(streams),
|
getPassphraseRetriever(streams),
|
||||||
|
@ -193,7 +193,7 @@ func getPassphraseRetriever(streams command.Streams) notary.PassRetriever {
|
||||||
return v, numAttempts > 1, nil
|
return v, numAttempts > 1, nil
|
||||||
}
|
}
|
||||||
// For non-root roles, we can also try the "default" alias if it is specified
|
// For non-root roles, we can also try the "default" alias if it is specified
|
||||||
if v := env["default"]; v != "" && alias != data.CanonicalRootRole {
|
if v := env["default"]; v != "" && alias != data.CanonicalRootRole.String() {
|
||||||
return v, numAttempts > 1, nil
|
return v, numAttempts > 1, nil
|
||||||
}
|
}
|
||||||
return baseRetriever(keyName, alias, createNew, numAttempts)
|
return baseRetriever(keyName, alias, createNew, numAttempts)
|
||||||
|
|
Loading…
Reference in New Issue