use walker for GetDelegationRole

Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
Riyaz Faizullabhoy 2016-02-18 14:19:24 -08:00
parent a7153aeccb
commit e279c99daf
1 changed files with 47 additions and 64 deletions

View File

@ -222,34 +222,48 @@ func (tr *Repo) GetDelegationRole(name string) (data.DelegationRole, error) {
}
// Traverse target metadata, down to delegation itself
// Get all public keys for the base role from TUF metadata
signedTargetData, ok := tr.Targets[data.CanonicalTargetsRole]
_, ok = tr.Targets[data.CanonicalTargetsRole]
if !ok {
return data.DelegationRole{}, ErrNotLoaded{data.CanonicalTargetsRole}
}
// Start with top level roles in targets. Walk the chain of ancestors
// until finding the desired role, or we run out of targets files to search.
delegationRoles := signedTargetData.Signed.Delegations.Roles
var foundRole *data.Role
for len(delegationRoles) > 0 {
delgRole := delegationRoles[0]
delegationRoles = delegationRoles[1:]
// If we found the role, we can exit the loop
if delgRole.Name == name {
foundRole = delgRole
break
var foundRole *data.DelegationRole
buildDelegationRoleVisitor := func(tgt *data.SignedTargets, roleName string) error {
if tgt == nil {
return ErrContinueWalk{}
}
// If the current role is an ancestor of our desired role, add its children
// to the queue of roles to investigate.
if strings.HasPrefix(name, delgRole.Name+"/") {
if delegationMeta, ok := tr.Targets[delgRole.Name]; ok {
delegationRoles = append(delegationRoles, delegationMeta.Signed.Delegations.Roles...)
// Try to find the delegation and build a DelegationRole structure
for _, role := range tgt.Signed.Delegations.Roles {
if role.Name == name {
pubKeys := make(map[string]data.PublicKey)
for _, keyID := range role.KeyIDs {
pubKey, ok := tgt.Signed.Delegations.Keys[keyID]
if !ok {
// Couldn't retrieve all keys, so stop walking
return ErrStopWalk{}
}
pubKeys[keyID] = pubKey
}
foundRole = &data.DelegationRole{
BaseRole: data.BaseRole{
Name: role.Name,
Keys: pubKeys,
Threshold: role.Threshold,
},
Paths: role.Paths,
}
return ErrStopWalk{}
}
}
return ErrContinueWalk{}
}
// Walk to the parent of this delegation, since that is where its role metadata exists
tr.WalkTargets("", path.Dir(name), buildDelegationRoleVisitor)
// We never found the delegation. In the context of this repo it is considered
// invalid. N.B. it may be that it existed at one point but an ancestor has since
// been modified/removed.
@ -257,33 +271,7 @@ func (tr *Repo) GetDelegationRole(name string) (data.DelegationRole, error) {
return data.DelegationRole{}, data.ErrInvalidRole{Role: name, Reason: "delegation does not exist"}
}
pubKeys := make(map[string]data.PublicKey)
parentRoleName := path.Dir(foundRole.Name)
parentData, ok := tr.Targets[parentRoleName]
if !ok {
// This should be impossible to reach given we inspected the parent to
// get foundRole
return data.DelegationRole{}, ErrNotLoaded{parentRoleName}
}
for _, keyID := range foundRole.KeyIDs {
pubKey, ok := parentData.Signed.Delegations.Keys[keyID]
if !ok {
return data.DelegationRole{}, data.ErrInvalidRole{
Role: name,
Reason: fmt.Sprintf("key with ID %s was not found in %s's metadata", keyID, parentRoleName),
}
}
pubKeys[keyID] = pubKey
}
return data.DelegationRole{
BaseRole: data.BaseRole{
Name: name,
Keys: pubKeys,
Threshold: foundRole.Threshold,
},
Paths: foundRole.Paths,
}, nil
return *foundRole, nil
}
// GetAllLoadedRoles returns a list of all role entries loaded in this TUF repo, could be empty
@ -620,14 +608,15 @@ type walkVisitorFunc func(*data.SignedTargets, string) error
// to call the visitor function on.
func (tr *Repo) WalkTargets(targetPath, rolePath string, visitTarget walkVisitorFunc) error {
// Start with the base targets role, which implicitly has the "" targets path
targetsRole, err := tr.GetBaseRole(data.CanonicalTargetsRole)
if err != nil {
return err
targetsRole, ok := tr.Root.Signed.Roles[data.CanonicalTargetsRole]
if !ok {
return data.ErrInvalidRole{Role: data.CanonicalTargetsRole, Reason: "role not found in root file"}
}
// Make the targets role have the empty path, when we treat it as a delegation role
roles := []data.DelegationRole{
roles := []*data.Role{
{
BaseRole: targetsRole,
RootRole: *targetsRole,
Name: data.CanonicalTargetsRole,
Paths: []string{""},
},
}
@ -645,34 +634,22 @@ func (tr *Repo) WalkTargets(targetPath, rolePath string, visitTarget walkVisitor
// We're at a prefix of the desired role subtree, so add its delegation role children and continue walking
if strings.HasPrefix(rolePath, role.Name+"/") {
for _, delgRole := range tr.Targets[role.Name].Signed.Delegations.Roles {
delegationRole, err := tr.GetDelegationRole(delgRole.Name)
if err != nil {
return err
}
roles = append(roles, delegationRole)
}
roles = append(roles, signedTgt.Signed.Delegations.Roles...)
continue
}
// Determine whether to visit this role or not:
// If the paths validate against the specified targetPath and the rolePath is empty or is in the subtree
if role.CheckPaths(targetPath) && isAncestorRole(role.Name, rolePath) {
if isValidPath(targetPath, role) && isAncestorRole(role.Name, rolePath) {
// If we had matching path or role name, visit this target and determine whether or not to keep walking
err = visitTarget(signedTgt, role.Name)
err := visitTarget(signedTgt, role.Name)
switch err.(type) {
case ErrStopWalk:
// If the visitor function signalled a stop, return nil to finish the walk
return nil
case ErrContinueWalk:
// If the visitor function signalled to continue, add this role's delegation to the walk
for _, delgRole := range tr.Targets[role.Name].Signed.Delegations.Roles {
delegationRole, err := tr.GetDelegationRole(delgRole.Name)
if err != nil {
return err
}
roles = append(roles, delegationRole)
}
roles = append(roles, signedTgt.Signed.Delegations.Roles...)
default:
// Return out if we got a different error or nil
return err
@ -689,6 +666,12 @@ func isAncestorRole(candidateChild, candidateAncestor string) bool {
return candidateAncestor == "" || candidateAncestor == candidateChild || strings.HasPrefix(candidateChild, candidateAncestor+"/")
}
// helper function that returns whether the delegation Role is valid against the given path
// Will return true if given an empty candidatePath
func isValidPath(candidatePath string, delgRole *data.Role) bool {
return candidatePath == "" || delgRole.CheckPaths(candidatePath)
}
// AddTargets will attempt to add the given targets specifically to
// the directed role. If the metadata for the role doesn't exist yet,
// AddTargets will create one.