delegation.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package targets
  2. import (
  3. "errors"
  4. "github.com/DataDog/go-tuf/data"
  5. "github.com/DataDog/go-tuf/internal/sets"
  6. "github.com/DataDog/go-tuf/verify"
  7. )
  8. type Delegation struct {
  9. Delegator string
  10. Delegatee data.DelegatedRole
  11. DB *verify.DB
  12. }
  13. type delegationsIterator struct {
  14. stack []Delegation
  15. target string
  16. visitedRoles map[string]struct{}
  17. }
  18. var ErrTopLevelTargetsRoleMissing = errors.New("tuf: top level targets role missing from top level keys DB")
  19. // NewDelegationsIterator initialises an iterator with a first step
  20. // on top level targets.
  21. func NewDelegationsIterator(target string, topLevelKeysDB *verify.DB) (*delegationsIterator, error) {
  22. targetsRole := topLevelKeysDB.GetRole("targets")
  23. if targetsRole == nil {
  24. return nil, ErrTopLevelTargetsRoleMissing
  25. }
  26. i := &delegationsIterator{
  27. target: target,
  28. stack: []Delegation{
  29. {
  30. Delegatee: data.DelegatedRole{
  31. Name: "targets",
  32. KeyIDs: sets.StringSetToSlice(targetsRole.KeyIDs),
  33. Threshold: targetsRole.Threshold,
  34. },
  35. DB: topLevelKeysDB,
  36. },
  37. },
  38. visitedRoles: make(map[string]struct{}),
  39. }
  40. return i, nil
  41. }
  42. func (d *delegationsIterator) Next() (value Delegation, ok bool) {
  43. if len(d.stack) == 0 {
  44. return Delegation{}, false
  45. }
  46. delegation := d.stack[len(d.stack)-1]
  47. d.stack = d.stack[:len(d.stack)-1]
  48. // 5.6.7.1: If this role has been visited before, then skip this role (so
  49. // that cycles in the delegation graph are avoided).
  50. roleName := delegation.Delegatee.Name
  51. if _, ok := d.visitedRoles[roleName]; ok {
  52. return d.Next()
  53. }
  54. d.visitedRoles[roleName] = struct{}{}
  55. // 5.6.7.2 trim delegations to visit, only the current role and its delegations
  56. // will be considered
  57. // https://github.com/DataDog/specification/issues/168
  58. if delegation.Delegatee.Terminating {
  59. // Empty the stack.
  60. d.stack = d.stack[0:0]
  61. }
  62. return delegation, true
  63. }
  64. func (d *delegationsIterator) Add(roles []data.DelegatedRole, delegator string, db *verify.DB) error {
  65. for i := len(roles) - 1; i >= 0; i-- {
  66. // Push the roles onto the stack in reverse so we get an preorder traversal
  67. // of the delegations graph.
  68. r := roles[i]
  69. matchesPath, err := r.MatchesPath(d.target)
  70. if err != nil {
  71. return err
  72. }
  73. if matchesPath {
  74. delegation := Delegation{
  75. Delegator: delegator,
  76. Delegatee: r,
  77. DB: db,
  78. }
  79. d.stack = append(d.stack, delegation)
  80. }
  81. }
  82. return nil
  83. }