mirror of https://github.com/docker/docs.git
PoC broken down client api for delegations
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
parent
2fac65df71
commit
70ee4f8670
|
@ -88,6 +88,7 @@ type TufDelegation struct {
|
|||
RemoveKeys []string `json:"remove_keys,omitempty"`
|
||||
AddPaths []string `json:"add_paths,omitempty"`
|
||||
RemovePaths []string `json:"remove_paths,omitempty"`
|
||||
ClearAllPaths bool `json:"clear_paths,omitempty"`
|
||||
AddPathHashPrefixes []string `json:"add_prefixes,omitempty"`
|
||||
RemovePathHashPrefixes []string `json:"remove_prefixes,omitempty"`
|
||||
}
|
||||
|
|
227
client/client.go
227
client/client.go
|
@ -302,12 +302,28 @@ func addChange(cl *changelist.FileChangelist, c changelist.Change, roles ...stri
|
|||
return nil
|
||||
}
|
||||
|
||||
// AddDelegation creates a new changelist entry to add a delegation to the repository
|
||||
// when the changelist gets applied at publish time. This does not do any validation
|
||||
// other than checking the name of the delegation to add - all that will happen
|
||||
// at publish time.
|
||||
func (r *NotaryRepository) AddDelegation(name string, threshold int,
|
||||
delegationKeys []data.PublicKey, paths []string) error {
|
||||
// AddDelegation creates changelist entries to add provided delegation public keys and paths.
|
||||
// This method composes AddDelegationRoleAndKeys and AddDelegationPaths (each creates one changelist if called).
|
||||
func (r *NotaryRepository) AddDelegation(name string, delegationKeys []data.PublicKey, paths []string) error {
|
||||
if len(delegationKeys) > 0 {
|
||||
err := r.AddDelegationRoleAndKeys(name, delegationKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(paths) > 0 {
|
||||
err := r.AddDelegationPaths(name, paths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
// one key upon creation to be valid since we will reject the changelist while validating the threshold.
|
||||
func (r *NotaryRepository) AddDelegationRoleAndKeys(name string, delegationKeys []data.PublicKey) error {
|
||||
|
||||
if !data.IsDelegation(name) {
|
||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||
|
@ -320,33 +336,68 @@ func (r *NotaryRepository) AddDelegation(name string, threshold int,
|
|||
defer cl.Close()
|
||||
|
||||
logrus.Debugf(`Adding delegation "%s" with threshold %d, and %d keys\n`,
|
||||
name, threshold, len(delegationKeys))
|
||||
name, notary.MinThreshold, len(delegationKeys))
|
||||
|
||||
// Defaulting to threshold of 1, since we don't allow for larger thresholds at the moment.
|
||||
tdJSON, err := json.Marshal(&changelist.TufDelegation{
|
||||
NewThreshold: threshold,
|
||||
NewThreshold: notary.MinThreshold,
|
||||
AddKeys: data.KeyList(delegationKeys),
|
||||
AddPaths: paths,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template := changelist.NewTufChange(
|
||||
changelist.ActionCreate,
|
||||
name,
|
||||
changelist.TypeTargetsDelegation,
|
||||
"", // no path
|
||||
tdJSON,
|
||||
)
|
||||
|
||||
template := newCreateDelegationChange(name, tdJSON)
|
||||
return addChange(cl, template, name)
|
||||
}
|
||||
|
||||
// RemoveDelegation creates a new changelist entry to remove a delegation from
|
||||
// the repository when the changelist gets applied at publish time.
|
||||
// This does not validate that the delegation exists, since one might exist
|
||||
// after applying all changes.
|
||||
func (r *NotaryRepository) RemoveDelegation(name string, keyIDs, paths []string, removeAll bool) error {
|
||||
// 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.
|
||||
func (r *NotaryRepository) AddDelegationPaths(name string, paths []string) error {
|
||||
|
||||
if !data.IsDelegation(name) {
|
||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||
}
|
||||
|
||||
cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cl.Close()
|
||||
|
||||
logrus.Debugf(`Adding delegation "%s" with threshold %d, and %s paths\n`, name, paths)
|
||||
|
||||
tdJSON, err := json.Marshal(&changelist.TufDelegation{
|
||||
AddPaths: paths,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template := newCreateDelegationChange(name, tdJSON)
|
||||
return addChange(cl, template, name)
|
||||
}
|
||||
|
||||
// RemoveDelegationKeysAndPaths creates changelist entries to remove provided delegation key IDs and paths.
|
||||
// This method composes RemoveDelegationPaths and RemoveDelegationKeys (each creates one changelist if called).
|
||||
func (r *NotaryRepository) RemoveDelegationKeysAndPaths(name string, keyIDs, paths []string) error {
|
||||
if len(paths) > 0 {
|
||||
err := r.RemoveDelegationPaths(name, paths)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(keyIDs) > 0 {
|
||||
err := r.RemoveDelegationKeys(name, keyIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 string) error {
|
||||
|
||||
if !data.IsDelegation(name) {
|
||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||
|
@ -359,39 +410,121 @@ func (r *NotaryRepository) RemoveDelegation(name string, keyIDs, paths []string,
|
|||
defer cl.Close()
|
||||
|
||||
logrus.Debugf(`Removing delegation "%s"\n`, name)
|
||||
var template *changelist.TufChange
|
||||
|
||||
// We use the Delete action only for force removal, Update is used for removing individual keys and paths
|
||||
if removeAll {
|
||||
template = changelist.NewTufChange(
|
||||
changelist.ActionDelete,
|
||||
name,
|
||||
changelist.TypeTargetsDelegation,
|
||||
"", // no path
|
||||
nil, // deleting role, no data needed
|
||||
)
|
||||
template := newDeleteDelegationChange(name, nil)
|
||||
return addChange(cl, template, name)
|
||||
}
|
||||
|
||||
} else {
|
||||
tdJSON, err := json.Marshal(&changelist.TufDelegation{
|
||||
RemoveKeys: keyIDs,
|
||||
RemovePaths: paths,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// RemoveDelegationPaths creates a changelist entry to remove provided paths from an existing delegation.
|
||||
func (r *NotaryRepository) RemoveDelegationPaths(name string, paths []string) error {
|
||||
|
||||
template = changelist.NewTufChange(
|
||||
changelist.ActionUpdate,
|
||||
name,
|
||||
changelist.TypeTargetsDelegation,
|
||||
"", // no path
|
||||
tdJSON,
|
||||
)
|
||||
if !data.IsDelegation(name) {
|
||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||
}
|
||||
|
||||
cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cl.Close()
|
||||
|
||||
logrus.Debugf(`Removing %s paths from delegation "%s"\n`, paths, name)
|
||||
|
||||
tdJSON, err := json.Marshal(&changelist.TufDelegation{
|
||||
RemovePaths: paths,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template := newUpdateDelegationChange(name, tdJSON)
|
||||
return addChange(cl, template, name)
|
||||
}
|
||||
|
||||
// RemoveDelegationKeys creates a changelist entry to remove provided keys from an existing delegation.
|
||||
// When this changelist is applied, if the specified keys are the only keys left in the role,
|
||||
// the role itself will be deleted in its entirety.
|
||||
func (r *NotaryRepository) RemoveDelegationKeys(name string, keyIDs []string) error {
|
||||
|
||||
if !data.IsDelegation(name) {
|
||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||
}
|
||||
|
||||
cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cl.Close()
|
||||
|
||||
logrus.Debugf(`Removing %s keys from delegation "%s"\n`, keyIDs, name)
|
||||
|
||||
tdJSON, err := json.Marshal(&changelist.TufDelegation{
|
||||
RemoveKeys: keyIDs,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template := newUpdateDelegationChange(name, tdJSON)
|
||||
return addChange(cl, template, name)
|
||||
}
|
||||
|
||||
// ClearDelegationPaths creates a changelist entry to remove all paths from an existing delegation.
|
||||
func (r *NotaryRepository) ClearDelegationPaths(name string) error {
|
||||
|
||||
if !data.IsDelegation(name) {
|
||||
return data.ErrInvalidRole{Role: name, Reason: "invalid delegation role name"}
|
||||
}
|
||||
|
||||
cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cl.Close()
|
||||
|
||||
logrus.Debugf(`Removing all paths from delegation "%s"\n`, name)
|
||||
|
||||
tdJSON, err := json.Marshal(&changelist.TufDelegation{
|
||||
ClearAllPaths: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template := newUpdateDelegationChange(name, tdJSON)
|
||||
return addChange(cl, template, name)
|
||||
}
|
||||
|
||||
func newUpdateDelegationChange(name string, content []byte) *changelist.TufChange {
|
||||
return changelist.NewTufChange(
|
||||
changelist.ActionUpdate,
|
||||
name,
|
||||
changelist.TypeTargetsDelegation,
|
||||
"", // no path for delegations
|
||||
content,
|
||||
)
|
||||
}
|
||||
|
||||
func newCreateDelegationChange(name string, content []byte) *changelist.TufChange {
|
||||
return changelist.NewTufChange(
|
||||
changelist.ActionCreate,
|
||||
name,
|
||||
changelist.TypeTargetsDelegation,
|
||||
"", // no path for delegations
|
||||
content,
|
||||
)
|
||||
}
|
||||
|
||||
func newDeleteDelegationChange(name string, content []byte) *changelist.TufChange {
|
||||
return changelist.NewTufChange(
|
||||
changelist.ActionDelete,
|
||||
name,
|
||||
changelist.TypeTargetsDelegation,
|
||||
"", // no path for delegations
|
||||
content,
|
||||
)
|
||||
}
|
||||
|
||||
// AddTarget creates new changelist entries to add a target to the given roles
|
||||
// in the repository when the changelist gets applied at publish time.
|
||||
// If roles are unspecified, the default role is "targets".
|
||||
|
|
|
@ -1910,10 +1910,10 @@ func testPublishDelegations(t *testing.T, clearCache, x509Keys bool) {
|
|||
// targets/a, because these should execute in order
|
||||
for _, delgName := range []string{"targets/a", "targets/a/b", "targets/c"} {
|
||||
assert.NoError(t,
|
||||
repo1.AddDelegation(delgName, 1, []data.PublicKey{delgKey}, []string{""}),
|
||||
repo1.AddDelegation(delgName, []data.PublicKey{delgKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
}
|
||||
assert.Len(t, getChanges(t, repo1), 3, "wrong number of changelist files found")
|
||||
assert.Len(t, getChanges(t, repo1), 6, "wrong number of changelist files found")
|
||||
|
||||
var rec *passRoleRecorder
|
||||
if clearCache {
|
||||
|
@ -1932,11 +1932,11 @@ func testPublishDelegations(t *testing.T, clearCache, x509Keys bool) {
|
|||
|
||||
// this should not publish, because targets/z doesn't exist
|
||||
assert.NoError(t,
|
||||
repo1.AddDelegation("targets/z/y", 1, []data.PublicKey{delgKey}, []string{""}),
|
||||
repo1.AddDelegation("targets/z/y", []data.PublicKey{delgKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
assert.Len(t, getChanges(t, repo1), 1, "wrong number of changelist files found")
|
||||
assert.Len(t, getChanges(t, repo1), 2, "wrong number of changelist files found")
|
||||
assert.Error(t, repo1.Publish())
|
||||
assert.Len(t, getChanges(t, repo1), 1, "wrong number of changelist files found")
|
||||
assert.Len(t, getChanges(t, repo1), 2, "wrong number of changelist files found")
|
||||
|
||||
if clearCache {
|
||||
rec.assertAsked(t, nil)
|
||||
|
@ -2035,7 +2035,7 @@ func testPublishTargetsDelgationScopeNoFallbackIfNoKeys(t *testing.T, clearCache
|
|||
}
|
||||
|
||||
// ensure that the role exists
|
||||
assert.NoError(t, repo.AddDelegation("targets/a", 1, []data.PublicKey{aPubKey}, []string{""}))
|
||||
assert.NoError(t, repo.AddDelegation("targets/a", []data.PublicKey{aPubKey}, []string{""}))
|
||||
assert.NoError(t, repo.Publish())
|
||||
|
||||
if clearCache {
|
||||
|
@ -2076,7 +2076,7 @@ func TestPublishTargetsDelgationSuccessLocallyHasRoles(t *testing.T) {
|
|||
for _, delgName := range []string{"targets/a", "targets/a/b"} {
|
||||
delgKey := createKey(t, repo, delgName, false)
|
||||
assert.NoError(t,
|
||||
repo.AddDelegation(delgName, 1, []data.PublicKey{delgKey}, []string{""}),
|
||||
repo.AddDelegation(delgName, []data.PublicKey{delgKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
}
|
||||
|
||||
|
@ -2106,7 +2106,7 @@ func TestPublishTargetsDelgationNoTargetsKeyNeeded(t *testing.T) {
|
|||
for _, delgName := range []string{"targets/a", "targets/a/b"} {
|
||||
delgKey := createKey(t, repo, delgName, false)
|
||||
assert.NoError(t,
|
||||
repo.AddDelegation(delgName, 1, []data.PublicKey{delgKey}, []string{""}),
|
||||
repo.AddDelegation(delgName, []data.PublicKey{delgKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
}
|
||||
|
||||
|
@ -2170,10 +2170,10 @@ func TestPublishTargetsDelgationSuccessNeedsToDownloadRoles(t *testing.T) {
|
|||
|
||||
// owner creates delegations, adds the delegated key to them, and publishes them
|
||||
assert.NoError(t,
|
||||
ownerRepo.AddDelegation("targets/a", 1, []data.PublicKey{aKey}, []string{""}),
|
||||
ownerRepo.AddDelegation("targets/a", []data.PublicKey{aKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
assert.NoError(t,
|
||||
ownerRepo.AddDelegation("targets/a/b", 1, []data.PublicKey{bKey}, []string{""}),
|
||||
ownerRepo.AddDelegation("targets/a/b", []data.PublicKey{bKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
|
||||
assert.NoError(t, ownerRepo.Publish())
|
||||
|
@ -2212,7 +2212,7 @@ func TestPublishTargetsDelgationFromTwoRepos(t *testing.T) {
|
|||
|
||||
// delegation includes both keys
|
||||
assert.NoError(t,
|
||||
repo1.AddDelegation("targets/a", 1, []data.PublicKey{key1, key2}, []string{""}),
|
||||
repo1.AddDelegation("targets/a", []data.PublicKey{key1, key2}, []string{""}),
|
||||
"error creating delegation")
|
||||
|
||||
assert.NoError(t, repo1.Publish())
|
||||
|
@ -2282,7 +2282,7 @@ func TestPublishRemoveDelgationKeyFromDelegationRole(t *testing.T) {
|
|||
|
||||
// owner creates delegation, adds the delegated key to it, and publishes it
|
||||
assert.NoError(t,
|
||||
ownerRepo.AddDelegation("targets/a", 1, []data.PublicKey{aKey}, []string{""}),
|
||||
ownerRepo.AddDelegation("targets/a", []data.PublicKey{aKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
assert.NoError(t, ownerRepo.Publish())
|
||||
|
||||
|
@ -2340,7 +2340,7 @@ func TestPublishRemoveDelgation(t *testing.T) {
|
|||
|
||||
// owner creates delegation, adds the delegated key to it, and publishes it
|
||||
assert.NoError(t,
|
||||
ownerRepo.AddDelegation("targets/a", 1, []data.PublicKey{aKey}, []string{""}),
|
||||
ownerRepo.AddDelegation("targets/a", []data.PublicKey{aKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
assert.NoError(t, ownerRepo.Publish())
|
||||
|
||||
|
@ -2351,7 +2351,7 @@ func TestPublishRemoveDelgation(t *testing.T) {
|
|||
// owner removes delegation
|
||||
aKeyCanonicalID, err := utils.CanonicalKeyID(aKey)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, ownerRepo.RemoveDelegation("targets/a", []string{aKeyCanonicalID}, []string{}, false))
|
||||
assert.NoError(t, ownerRepo.RemoveDelegationKeys("targets/a", []string{aKeyCanonicalID}))
|
||||
assert.NoError(t, ownerRepo.Publish())
|
||||
|
||||
// delegated repo can now no longer publish to delegated role
|
||||
|
@ -2374,7 +2374,7 @@ func TestPublishSucceedsDespiteDelegationCorrupt(t *testing.T) {
|
|||
assert.NoError(t, err, "error creating delegation key")
|
||||
|
||||
assert.NoError(t,
|
||||
repo.AddDelegation("targets/a", 1, []data.PublicKey{delgKey}, []string{""}),
|
||||
repo.AddDelegation("targets/a", []data.PublicKey{delgKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
|
||||
testPublishBadMetadata(t, "targets/a", repo, false, true)
|
||||
|
@ -2609,22 +2609,25 @@ func TestAddDelegationChangefileValid(t *testing.T) {
|
|||
targetPubKey := repo.CryptoService.GetKey(targetKeyIds[0])
|
||||
assert.NotNil(t, targetPubKey)
|
||||
|
||||
err := repo.AddDelegation("root", 1, []data.PublicKey{targetPubKey}, []string{""})
|
||||
err := repo.AddDelegation("root", []data.PublicKey{targetPubKey}, []string{""})
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, data.ErrInvalidRole{}, err)
|
||||
assert.Empty(t, getChanges(t, repo))
|
||||
|
||||
// to show that adding does not care about the hierarchy
|
||||
err = repo.AddDelegation("targets/a/b/c", 1, []data.PublicKey{targetPubKey}, []string{""})
|
||||
err = repo.AddDelegation("targets/a/b/c", []data.PublicKey{targetPubKey}, []string{""})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// ensure that the changefiles is correct
|
||||
changes := getChanges(t, repo)
|
||||
assert.Len(t, changes, 1)
|
||||
assert.Len(t, changes, 2)
|
||||
assert.Equal(t, changelist.ActionCreate, changes[0].Action())
|
||||
assert.Equal(t, "targets/a/b/c", changes[0].Scope())
|
||||
assert.Equal(t, changelist.TypeTargetsDelegation, changes[0].Type())
|
||||
assert.Equal(t, "", changes[0].Path())
|
||||
assert.Equal(t, changelist.ActionCreate, changes[1].Action())
|
||||
assert.Equal(t, "targets/a/b/c", changes[1].Scope())
|
||||
assert.Equal(t, changelist.TypeTargetsDelegation, changes[1].Type())
|
||||
assert.Equal(t, "", changes[1].Path())
|
||||
assert.NotEmpty(t, changes[0].Content())
|
||||
}
|
||||
|
||||
|
@ -2645,10 +2648,10 @@ func TestAddDelegationChangefileApplicable(t *testing.T) {
|
|||
assert.NotNil(t, targetPubKey)
|
||||
|
||||
// this hierarchy has to be right to be applied
|
||||
err := repo.AddDelegation("targets/a", 1, []data.PublicKey{targetPubKey}, []string{""})
|
||||
err := repo.AddDelegation("targets/a", []data.PublicKey{targetPubKey}, []string{""})
|
||||
assert.NoError(t, err)
|
||||
changes := getChanges(t, repo)
|
||||
assert.Len(t, changes, 1)
|
||||
assert.Len(t, changes, 2)
|
||||
|
||||
// ensure that it can be applied correctly
|
||||
err = applyTargetsChange(repo.tufRepo, changes[0])
|
||||
|
@ -2676,7 +2679,7 @@ func TestAddDelegationErrorWritingChanges(t *testing.T) {
|
|||
targetPubKey := repo.CryptoService.GetKey(targetKeyIds[0])
|
||||
assert.NotNil(t, targetPubKey)
|
||||
|
||||
return repo.AddDelegation("targets/a", 1, []data.PublicKey{targetPubKey}, []string{""})
|
||||
return repo.AddDelegation("targets/a", []data.PublicKey{targetPubKey}, []string{""})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2693,14 +2696,14 @@ func TestRemoveDelegationChangefileValid(t *testing.T) {
|
|||
rootPubKey := repo.CryptoService.GetKey(rootKeyID)
|
||||
assert.NotNil(t, rootPubKey)
|
||||
|
||||
err := repo.RemoveDelegation("root", []string{rootKeyID}, []string{}, false)
|
||||
err := repo.RemoveDelegationKeys("root", []string{rootKeyID})
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, data.ErrInvalidRole{}, err)
|
||||
assert.Empty(t, getChanges(t, repo))
|
||||
|
||||
// to demonstrate that so long as the delegation name is valid, the
|
||||
// existence of the delegation doesn't matter
|
||||
assert.NoError(t, repo.RemoveDelegation("targets/a/b/c", []string{rootKeyID}, []string{}, false))
|
||||
assert.NoError(t, repo.RemoveDelegationKeys("targets/a/b/c", []string{rootKeyID}))
|
||||
|
||||
// ensure that the changefile is correct
|
||||
changes := getChanges(t, repo)
|
||||
|
@ -2711,7 +2714,7 @@ func TestRemoveDelegationChangefileValid(t *testing.T) {
|
|||
assert.Equal(t, "", changes[0].Path())
|
||||
}
|
||||
|
||||
// The changefile produced by RemoveDelegation, when applied, actually removes
|
||||
// The changefile produced by RemoveDelegationKeys, when applied, actually removes
|
||||
// the delegation from the repo (assuming the repo exists - tests for
|
||||
// change application validation are in helpers_test.go)
|
||||
func TestRemoveDelegationChangefileApplicable(t *testing.T) {
|
||||
|
@ -2725,10 +2728,11 @@ func TestRemoveDelegationChangefileApplicable(t *testing.T) {
|
|||
assert.NotNil(t, rootPubKey)
|
||||
|
||||
// add a delegation first so it can be removed
|
||||
assert.NoError(t, repo.AddDelegation("targets/a", 1, []data.PublicKey{rootPubKey}, []string{""}))
|
||||
assert.NoError(t, repo.AddDelegation("targets/a", []data.PublicKey{rootPubKey}, []string{""}))
|
||||
changes := getChanges(t, repo)
|
||||
assert.Len(t, changes, 1)
|
||||
assert.Len(t, changes, 2)
|
||||
assert.NoError(t, applyTargetsChange(repo.tufRepo, changes[0]))
|
||||
assert.NoError(t, applyTargetsChange(repo.tufRepo, changes[1]))
|
||||
|
||||
targetRole := repo.tufRepo.Targets[data.CanonicalTargetsRole]
|
||||
assert.Len(t, targetRole.Signed.Delegations.Roles, 1)
|
||||
|
@ -2737,21 +2741,51 @@ func TestRemoveDelegationChangefileApplicable(t *testing.T) {
|
|||
// now remove it
|
||||
rootKeyCanonicalID, err := utils.CanonicalKeyID(rootPubKey)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, repo.RemoveDelegation("targets/a", []string{rootKeyCanonicalID}, []string{}, false))
|
||||
assert.NoError(t, repo.RemoveDelegationKeys("targets/a", []string{rootKeyCanonicalID}))
|
||||
changes = getChanges(t, repo)
|
||||
assert.Len(t, changes, 2)
|
||||
assert.NoError(t, applyTargetsChange(repo.tufRepo, changes[1]))
|
||||
assert.Len(t, changes, 3)
|
||||
assert.NoError(t, applyTargetsChange(repo.tufRepo, changes[2]))
|
||||
|
||||
targetRole = repo.tufRepo.Targets[data.CanonicalTargetsRole]
|
||||
assert.Empty(t, targetRole.Signed.Delegations.Roles)
|
||||
assert.Empty(t, targetRole.Signed.Delegations.Keys)
|
||||
}
|
||||
|
||||
// The changefile with the ClearAllPaths key, when applied, actually removes
|
||||
// all paths from the specified delegation in the repo (assuming the repo and delegation exist)
|
||||
func TestClearAllPathsDelegationChangefileApplicable(t *testing.T) {
|
||||
gun := "docker.com/notary"
|
||||
ts, _, _ := simpleTestServer(t)
|
||||
defer ts.Close()
|
||||
|
||||
repo, rootKeyID := initializeRepo(t, data.ECDSAKey, gun, ts.URL, false)
|
||||
defer os.RemoveAll(repo.baseDir)
|
||||
rootPubKey := repo.CryptoService.GetKey(rootKeyID)
|
||||
assert.NotNil(t, rootPubKey)
|
||||
|
||||
// add a delegation first so it can be removed
|
||||
assert.NoError(t, repo.AddDelegation("targets/a", []data.PublicKey{rootPubKey}, []string{"abc,123,xyz,path"}))
|
||||
changes := getChanges(t, repo)
|
||||
assert.Len(t, changes, 2)
|
||||
assert.NoError(t, applyTargetsChange(repo.tufRepo, changes[0]))
|
||||
assert.NoError(t, applyTargetsChange(repo.tufRepo, changes[1]))
|
||||
|
||||
// now clear paths it
|
||||
assert.NoError(t, repo.ClearDelegationPaths("targets/a"))
|
||||
changes = getChanges(t, repo)
|
||||
assert.Len(t, changes, 3)
|
||||
assert.NoError(t, applyTargetsChange(repo.tufRepo, changes[2]))
|
||||
|
||||
delgRoles := repo.tufRepo.Targets[data.CanonicalTargetsRole].Signed.Delegations.Roles
|
||||
assert.Len(t, delgRoles, 1)
|
||||
assert.Len(t, delgRoles[0].Paths, 0)
|
||||
}
|
||||
|
||||
// TestRemoveDelegationErrorWritingChanges expects errors writing a change to
|
||||
// file to be propagated.
|
||||
func TestRemoveDelegationErrorWritingChanges(t *testing.T) {
|
||||
testErrorWritingChangefiles(t, func(repo *NotaryRepository) error {
|
||||
return repo.RemoveDelegation("targets/a", []string{""}, []string{}, false)
|
||||
return repo.RemoveDelegationKeysAndPaths("targets/a", []string{""}, []string{})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2859,10 +2893,10 @@ func testPublishTargetsDelgationCanUseUserKeyWithArbitraryRole(t *testing.T, x50
|
|||
|
||||
// owner creates delegations, adds the delegated key to them, and publishes them
|
||||
assert.NoError(t,
|
||||
ownerRepo.AddDelegation("targets/a", 1, []data.PublicKey{aKey}, []string{""}),
|
||||
ownerRepo.AddDelegation("targets/a", []data.PublicKey{aKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
assert.NoError(t,
|
||||
ownerRepo.AddDelegation("targets/a/b", 1, []data.PublicKey{bKey}, []string{""}),
|
||||
ownerRepo.AddDelegation("targets/a/b", []data.PublicKey{bKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
|
||||
assert.NoError(t, ownerRepo.Publish())
|
||||
|
@ -3016,7 +3050,7 @@ func TestListRoles(t *testing.T) {
|
|||
// Create a delegation on the top level
|
||||
aKey := createKey(t, repo, "user", true)
|
||||
assert.NoError(t,
|
||||
repo.AddDelegation("targets/a", 1, []data.PublicKey{aKey}, []string{""}),
|
||||
repo.AddDelegation("targets/a", []data.PublicKey{aKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
|
||||
assert.NoError(t, repo.Publish())
|
||||
|
@ -3053,7 +3087,7 @@ func TestListRoles(t *testing.T) {
|
|||
// Create another delegation, one level further
|
||||
bKey := createKey(t, repo, "user", true)
|
||||
assert.NoError(t,
|
||||
repo.AddDelegation("targets/a/b", 1, []data.PublicKey{bKey}, []string{""}),
|
||||
repo.AddDelegation("targets/a/b", []data.PublicKey{bKey}, []string{""}),
|
||||
"error creating delegation")
|
||||
|
||||
assert.NoError(t, repo.Publish())
|
||||
|
|
|
@ -136,8 +136,13 @@ func changeTargetsDelegation(repo *tuf.Repo, c changelist.Change) error {
|
|||
if err := r.AddPathHashPrefixes(td.AddPathHashPrefixes); err != nil {
|
||||
return err
|
||||
}
|
||||
r.RemoveKeys(removeTUFKeyIDs)
|
||||
r.RemovePaths(td.RemovePaths)
|
||||
|
||||
// Clear all paths if we're given the flag, else remove specified paths
|
||||
if td.ClearAllPaths {
|
||||
r.RemovePaths(r.Paths)
|
||||
} else {
|
||||
r.RemovePaths(td.RemovePaths)
|
||||
}
|
||||
r.RemovePathHashPrefixes(td.RemovePathHashPrefixes)
|
||||
return repo.UpdateDelegations(r, td.AddKeys)
|
||||
case changelist.ActionDelete:
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/docker/notary"
|
||||
notaryclient "github.com/docker/notary/client"
|
||||
"github.com/docker/notary/passphrase"
|
||||
"github.com/docker/notary/trustmanager"
|
||||
|
@ -139,13 +138,19 @@ func (d *delegationCommander) delegationRemove(cmd *cobra.Command, args []string
|
|||
} else {
|
||||
cmd.Println("Confirmed `yes` from flag")
|
||||
}
|
||||
// Delete the entire delegation
|
||||
err = nRepo.RemoveDelegationRole(role)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to remove delegation: %v", err)
|
||||
}
|
||||
} else {
|
||||
// Remove any keys or paths that we passed in
|
||||
err = nRepo.RemoveDelegationKeysAndPaths(role, keyIDs, paths)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to remove delegation: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the delegation from the repository
|
||||
err = nRepo.RemoveDelegation(role, keyIDs, paths, removeAll)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to remove delegation: %v", err)
|
||||
}
|
||||
cmd.Println("")
|
||||
if removeAll {
|
||||
cmd.Printf("Forced removal (including all keys and paths) of delegation role %s to repository \"%s\" staged for next publish.\n", role, gun)
|
||||
|
@ -197,9 +202,7 @@ func (d *delegationCommander) delegationAdd(cmd *cobra.Command, args []string) e
|
|||
}
|
||||
|
||||
// Add the delegation to the repository
|
||||
// Sets threshold to 1 since we only added one key - thresholds are not currently fully supported, though
|
||||
// one can use additional client-side validation to check for signatures from a quorum of varying delegation roles
|
||||
err = nRepo.AddDelegation(role, notary.MinThreshold, pubKeys, paths)
|
||||
err = nRepo.AddDelegation(role, pubKeys, paths)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create delegation: %v", err)
|
||||
}
|
||||
|
|
|
@ -242,7 +242,6 @@ func (tr *Repo) UpdateDelegations(role *data.Role, keys []data.PublicKey) error
|
|||
p.Signed.Delegations.Keys[k.ID()] = k
|
||||
tr.keysDB.AddKey(k)
|
||||
}
|
||||
|
||||
// if the role has fewer keys than the threshold, it
|
||||
// will never be able to create a valid targets file
|
||||
// and should be considered invalid.
|
||||
|
|
Loading…
Reference in New Issue