download all delegated roles when doing downloadTargets

Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)
This commit is contained in:
David Lawrence 2015-12-15 15:15:37 -08:00
parent 90e22ff5ff
commit 33d39afdf5
2 changed files with 96 additions and 26 deletions

View File

@ -369,34 +369,47 @@ func (c *Client) downloadSnapshot() error {
return nil
}
// downloadTargets is responsible for downloading any targets file
// including delegates roles.
// 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
// to obtain the keys to validate children.
func (c *Client) downloadTargets(role string) error {
role = data.RoleName(role) // this will really only do something for base targets role
if c.local.Snapshot == nil {
return ErrMissingMeta{role: role}
}
snap := c.local.Snapshot.Signed
root := c.local.Root.Signed
r := c.keysDB.GetRole(role)
if r == nil {
return fmt.Errorf("Invalid role: %s", role)
}
keyIDs := r.KeyIDs
s, err := c.getTargetsFile(role, keyIDs, snap.Meta, root.ConsistentSnapshot, r.Threshold)
if err != nil {
logrus.Error("Error getting targets file:", err)
return err
}
t, err := data.TargetsFromSigned(s)
if err != nil {
return err
}
err = c.local.SetTargets(role, t)
if err != nil {
return err
}
stack := utils.NewStack()
stack.Push(role)
for !stack.Empty() {
role, err := stack.PopString()
if err != nil {
return err
}
role = data.RoleName(role) // this will really only do something for base targets role
if c.local.Snapshot == nil {
return ErrMissingMeta{role: role}
}
snap := c.local.Snapshot.Signed
root := c.local.Root.Signed
r := c.keysDB.GetRole(role)
if r == nil {
return fmt.Errorf("Invalid role: %s", role)
}
keyIDs := r.KeyIDs
s, err := c.getTargetsFile(role, keyIDs, snap.Meta, root.ConsistentSnapshot, r.Threshold)
if err != nil {
logrus.Error("Error getting targets file:", err)
return err
}
t, err := data.TargetsFromSigned(s)
if err != nil {
return err
}
err = c.local.SetTargets(role, t)
if err != nil {
return err
}
// push delegated roles contained in the targets file onto the stack
for _, r := range t.Signed.Delegations.Roles {
stack.Push(r.Name)
}
}
return nil
}

57
tuf/utils/stack.go Normal file
View File

@ -0,0 +1,57 @@
package utils
import (
"fmt"
)
type ErrEmptyStack struct {
action string
}
func (err ErrEmptyStack) Error() string {
return fmt.Sprintf("attempted to %s with empty stack", err.action)
}
type ErrBadTypeCast struct{}
func (err ErrBadTypeCast) Error() string {
return "attempted to do a typed pop and item was not of type"
}
type Stack []interface{}
func NewStack() *Stack {
s := make(Stack, 0)
return &s
}
func (s *Stack) Push(item interface{}) {
*s = append(*s, item)
}
func (s *Stack) Pop() (interface{}, error) {
l := len(*s)
if l > 0 {
item := (*s)[l-1]
*s = (*s)[:l-1]
return item, nil
}
return nil, ErrEmptyStack{action: "pop"}
}
func (s *Stack) PopString() (string, error) {
l := len(*s)
if l > 0 {
item := (*s)[l-1]
if item, ok := item.(string); ok {
*s = (*s)[:l-1]
return item, nil
}
return "", ErrBadTypeCast{}
}
return "", ErrEmptyStack{action: "pop"}
}
func (s Stack) Empty() bool {
return len(s) == 0
}