func TestApplyTargetsDelegationAlreadyExistingMergePaths(t *testing.T) { repo, cs, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) newKey, err := cs.Create("targets/level1", "docker.com/notary", data.ED25519Key) require.NoError(t, err) // create delegation kl := data.KeyList{newKey} td := &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, AddPaths: []string{"level1"}, } tdJSON, err := json.Marshal(td) require.NoError(t, err) ch := changelist.NewTUFChange( changelist.ActionCreate, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) // we have sufficient checks elsewhere we don't need to confirm that // creating fresh works here via more requires. // Use different path for this changelist td.AddPaths = []string{"level2"} tdJSON, err = json.Marshal(td) require.NoError(t, err) ch = changelist.NewTUFChange( changelist.ActionCreate, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON, ) // when attempting to create the same role again, check that we // merged with previous details err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) delegation, err := repo.GetDelegationRole("targets/level1") require.NoError(t, err) // Assert we have both paths require.Contains(t, delegation.Paths, "level2") require.Contains(t, delegation.Paths, "level1") }
// Witness creates change objects to witness (i.e. re-sign) the given // roles on the next publish. One change is created per role func (r *NotaryRepository) Witness(roles ...string) ([]string, error) { cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) if err != nil { return nil, err } defer cl.Close() successful := make([]string, 0, len(roles)) for _, role := range roles { // scope is role c := changelist.NewTUFChange( changelist.ActionUpdate, role, changelist.TypeWitness, "", nil, ) err = cl.Add(c) if err != nil { break } successful = append(successful, role) } return successful, err }
// Applying a delegation whose parent doesn't exist fails. func TestApplyTargetsDelegationParentDoesntExist(t *testing.T) { repo, cs, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) // make sure a key exists for the previous level, so it's not a missing // key error, but we don't care about this key _, err = cs.Create("targets/level1", "docker.com/notary", data.ED25519Key) require.NoError(t, err) newKey, err := cs.Create("targets/level1/level2", "docker.com/notary", data.ED25519Key) require.NoError(t, err) // create delegation kl := data.KeyList{newKey} td := &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, } tdJSON, err := json.Marshal(td) require.NoError(t, err) ch := changelist.NewTUFChange( changelist.ActionCreate, "targets/level1/level2", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.Error(t, err) require.IsType(t, data.ErrInvalidRole{}, err) }
func TestApplyTargetsDelegationInvalidJSONContent(t *testing.T) { repo, cs, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) newKey, err := cs.Create("targets/level1", "docker.com/notary", data.ED25519Key) require.NoError(t, err) // create delegation kl := data.KeyList{newKey} td := &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, AddPaths: []string{"level1"}, } tdJSON, err := json.Marshal(td) require.NoError(t, err) ch := changelist.NewTUFChange( changelist.ActionCreate, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON[1:], ) err = applyTargetsChange(repo, nil, ch) require.Error(t, err) }
// adds a TUF Change template to the given roles func addChange(cl *changelist.FileChangelist, c changelist.Change, roles ...string) error { if len(roles) == 0 { roles = []string{data.CanonicalTargetsRole} } var changes []changelist.Change for _, role := range roles { // Ensure we can only add targets to the CanonicalTargetsRole, // or a Delegation role (which is <CanonicalTargetsRole>/something else) if role != data.CanonicalTargetsRole && !data.IsDelegation(role) { return data.ErrInvalidRole{ Role: role, Reason: "cannot add targets to this role", } } changes = append(changes, changelist.NewTUFChange( c.Action(), role, c.Type(), c.Path(), c.Content(), )) } for _, c := range changes { if err := cl.Add(c); err != nil { return err } } return nil }
func newDeleteDelegationChange(name string, content []byte) *changelist.TUFChange { return changelist.NewTUFChange( changelist.ActionDelete, name, changelist.TypeTargetsDelegation, "", // no path for delegations content, ) }
// RemoveTarget creates new changelist entries to remove a target from the given // roles in the repository when the changelist gets applied at publish time. // If roles are unspecified, the default role is "target". func (r *NotaryRepository) RemoveTarget(targetName string, roles ...string) error { cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) if err != nil { return err } logrus.Debugf("Removing target \"%s\"", targetName) template := changelist.NewTUFChange(changelist.ActionDelete, "", changelist.TypeTargetsTarget, targetName, nil) return addChange(cl, template, roles...) }
func TestApplyTargetsChangeInvalidType(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) ch := changelist.NewTUFChange( changelist.ActionCreate, "targets/level1", "badType", "", nil, ) err = applyTargetsChange(repo, nil, ch) require.Error(t, err) }
func TestApplyTargetsDelegationInvalidAction(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) ch := changelist.NewTUFChange( "bad action", "targets/level1", changelist.TypeTargetsDelegation, "", nil, ) err = applyTargetsChange(repo, nil, ch) require.Error(t, err) }
func (r *NotaryRepository) rootFileKeyChange(cl changelist.Changelist, role, action string, key data.PublicKey) error { kl := make(data.KeyList, 0, 1) kl = append(kl, key) meta := changelist.TUFRootData{ RoleName: role, Keys: kl, } metaJSON, err := json.Marshal(meta) if err != nil { return err } c := changelist.NewTUFChange( action, changelist.ScopeRoot, changelist.TypeRootRole, role, metaJSON, ) return cl.Add(c) }
// 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" func (r *NotaryRepository) AddTarget(target *Target, roles ...string) error { if len(target.Hashes) == 0 { return fmt.Errorf("no hashes specified for target \"%s\"", target.Name) } cl, err := changelist.NewFileChangelist(filepath.Join(r.tufRepoPath, "changelist")) if err != nil { return err } defer cl.Close() logrus.Debugf("Adding target \"%s\" with sha256 \"%x\" and size %d bytes.\n", target.Name, target.Hashes["sha256"], target.Length) meta := data.FileMeta{Length: target.Length, Hashes: target.Hashes} metaJSON, err := json.Marshal(meta) if err != nil { return err } template := changelist.NewTUFChange( changelist.ActionCreate, "", changelist.TypeTargetsTarget, target.Name, metaJSON) return addChange(cl, template, roles...) }
func TestApplyTargetsDelegationCreate2Deep(t *testing.T) { repo, cs, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) newKey, err := cs.Create("targets/level1", "docker.com/notary", data.ED25519Key) require.NoError(t, err) // create delegation kl := data.KeyList{newKey} td := &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, AddPaths: []string{"level1"}, } tdJSON, err := json.Marshal(td) require.NoError(t, err) ch := changelist.NewTUFChange( changelist.ActionCreate, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) tgts := repo.Targets[data.CanonicalTargetsRole] require.Len(t, tgts.Signed.Delegations.Roles, 1) require.Len(t, tgts.Signed.Delegations.Keys, 1) _, ok := tgts.Signed.Delegations.Keys[newKey.ID()] require.True(t, ok) role := tgts.Signed.Delegations.Roles[0] require.Len(t, role.KeyIDs, 1) require.Equal(t, newKey.ID(), role.KeyIDs[0]) require.Equal(t, "targets/level1", role.Name) require.Equal(t, "level1", role.Paths[0]) // init delegations targets file. This would be done as part of a publish // operation repo.InitTargets("targets/level1") td = &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, AddPaths: []string{"level1/level2"}, } tdJSON, err = json.Marshal(td) require.NoError(t, err) ch = changelist.NewTUFChange( changelist.ActionCreate, "targets/level1/level2", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) tgts = repo.Targets["targets/level1"] require.Len(t, tgts.Signed.Delegations.Roles, 1) require.Len(t, tgts.Signed.Delegations.Keys, 1) _, ok = tgts.Signed.Delegations.Keys[newKey.ID()] require.True(t, ok) role = tgts.Signed.Delegations.Roles[0] require.Len(t, role.KeyIDs, 1) require.Equal(t, newKey.ID(), role.KeyIDs[0]) require.Equal(t, "targets/level1/level2", role.Name) require.Equal(t, "level1/level2", role.Paths[0]) }
func TestApplyTargetsDelegationCreateAlreadyExisting(t *testing.T) { repo, cs, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) newKey, err := cs.Create("targets/level1", "docker.com/notary", data.ED25519Key) require.NoError(t, err) // create delegation kl := data.KeyList{newKey} td := &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, AddPaths: []string{"level1"}, } tdJSON, err := json.Marshal(td) require.NoError(t, err) ch := changelist.NewTUFChange( changelist.ActionCreate, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) // we have sufficient checks elsewhere we don't need to confirm that // creating fresh works here via more requires. extraKey, err := cs.Create("targets/level1", "docker.com/notary", data.ED25519Key) require.NoError(t, err) // create delegation kl = data.KeyList{extraKey} td = &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, AddPaths: []string{"level1"}, } tdJSON, err = json.Marshal(td) require.NoError(t, err) ch = changelist.NewTUFChange( changelist.ActionCreate, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON, ) // when attempting to create the same role again, check that we added a key err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) delegation, err := repo.GetDelegationRole("targets/level1") require.NoError(t, err) require.Contains(t, delegation.Paths, "level1") require.Equal(t, len(delegation.ListKeyIDs()), 2) }
func TestApplyTargetsDelegationCreateEdit(t *testing.T) { repo, cs, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) newKey, err := cs.Create("targets/level1", "docker.com/notary", data.ED25519Key) require.NoError(t, err) // create delegation kl := data.KeyList{newKey} td := &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, AddPaths: []string{"level1"}, } tdJSON, err := json.Marshal(td) require.NoError(t, err) ch := changelist.NewTUFChange( changelist.ActionCreate, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) // edit delegation newKey2, err := cs.Create("targets/level1", "docker.com/notary", data.ED25519Key) require.NoError(t, err) kl = data.KeyList{newKey2} td = &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, RemoveKeys: []string{newKey.ID()}, } tdJSON, err = json.Marshal(td) require.NoError(t, err) ch = changelist.NewTUFChange( changelist.ActionUpdate, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) tgts := repo.Targets[data.CanonicalTargetsRole] require.Len(t, tgts.Signed.Delegations.Roles, 1) require.Len(t, tgts.Signed.Delegations.Keys, 1) _, ok := tgts.Signed.Delegations.Keys[newKey2.ID()] require.True(t, ok) role := tgts.Signed.Delegations.Roles[0] require.Len(t, role.KeyIDs, 1) require.Equal(t, newKey2.ID(), role.KeyIDs[0]) require.Equal(t, "targets/level1", role.Name) require.Equal(t, "level1", role.Paths[0]) }
func TestApplyTargetsDelegationCreate2SharedKey(t *testing.T) { repo, cs, err := testutils.EmptyRepo("docker.com/notary") require.NoError(t, err) newKey, err := cs.Create("targets/level1", "docker.com/notary", data.ED25519Key) require.NoError(t, err) // create first delegation kl := data.KeyList{newKey} td := &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, AddPaths: []string{"level1"}, } tdJSON, err := json.Marshal(td) require.NoError(t, err) ch := changelist.NewTUFChange( changelist.ActionCreate, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) // create second delegation kl = data.KeyList{newKey} td = &changelist.TUFDelegation{ NewThreshold: 1, AddKeys: kl, AddPaths: []string{"level2"}, } tdJSON, err = json.Marshal(td) require.NoError(t, err) ch = changelist.NewTUFChange( changelist.ActionCreate, "targets/level2", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) tgts := repo.Targets[data.CanonicalTargetsRole] require.Len(t, tgts.Signed.Delegations.Roles, 2) require.Len(t, tgts.Signed.Delegations.Keys, 1) role1 := tgts.Signed.Delegations.Roles[0] require.Len(t, role1.KeyIDs, 1) require.Equal(t, newKey.ID(), role1.KeyIDs[0]) require.Equal(t, "targets/level1", role1.Name) require.Equal(t, "level1", role1.Paths[0]) role2 := tgts.Signed.Delegations.Roles[1] require.Len(t, role2.KeyIDs, 1) require.Equal(t, newKey.ID(), role2.KeyIDs[0]) require.Equal(t, "targets/level2", role2.Name) require.Equal(t, "level2", role2.Paths[0]) // delete one delegation, ensure shared key remains td = &changelist.TUFDelegation{ RemoveKeys: []string{newKey.ID()}, } tdJSON, err = json.Marshal(td) require.NoError(t, err) ch = changelist.NewTUFChange( changelist.ActionDelete, "targets/level1", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) require.Len(t, tgts.Signed.Delegations.Roles, 1) require.Len(t, tgts.Signed.Delegations.Keys, 1) // delete other delegation, ensure key cleaned up ch = changelist.NewTUFChange( changelist.ActionDelete, "targets/level2", changelist.TypeTargetsDelegation, "", tdJSON, ) err = applyTargetsChange(repo, nil, ch) require.NoError(t, err) require.Len(t, tgts.Signed.Delegations.Roles, 0) require.Len(t, tgts.Signed.Delegations.Keys, 0) }