1 package targets
2
3 import (
4 "testing"
5
6 "github.com/stretchr/testify/assert"
7 "github.com/theupdateframework/go-tuf/data"
8 "github.com/theupdateframework/go-tuf/verify"
9 )
10
11 var (
12 defaultPathPatterns = []string{"tmp", "*"}
13 noMatchPathPatterns = []string{"vars", "null"}
14 )
15
16 func TestDelegationsIterator(t *testing.T) {
17 topTargetsPubKey := &data.PublicKey{
18 Type: data.KeyTypeEd25519,
19 Scheme: data.KeySchemeEd25519,
20 Algorithms: data.HashAlgorithms,
21 Value: []byte(`{"public":"aaaaec567e5901ba3976c34f7cd5169704292439bf71e6aa19c64b96706f95ef"}`),
22 }
23 delTargetsPubKey := &data.PublicKey{
24 Type: data.KeyTypeEd25519,
25 Scheme: data.KeySchemeEd25519,
26 Algorithms: data.HashAlgorithms,
27 Value: []byte(`{"public":"bbbbec567e5901ba3976c34f7cd5169704292439bf71e6aa19c64b96706f95ef"}`),
28 }
29
30 defaultKeyIDs := delTargetsPubKey.IDs()
31 var iteratorTests = []struct {
32 testName string
33 roles map[string][]data.DelegatedRole
34 file string
35 resultOrder []string
36 err error
37 }{
38 {
39 testName: "no delegation",
40 roles: map[string][]data.DelegatedRole{
41 "targets": {},
42 },
43 file: "test.txt",
44 resultOrder: []string{"targets"},
45 },
46 {
47 testName: "no termination",
48 roles: map[string][]data.DelegatedRole{
49 "targets": {
50 {Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
51 {Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
52 },
53 "b": {
54 {Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
55 },
56 "c": {
57 {Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
58 },
59 "e": {
60 {Name: "f", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
61 {Name: "g", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
62 },
63 "g": {
64 {Name: "h", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
65 {Name: "i", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
66 {Name: "j", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
67 },
68 },
69 file: "",
70 resultOrder: []string{"targets", "b", "c", "d", "e", "f", "g", "h", "i", "j"},
71 },
72 {
73 testName: "terminated in b",
74 roles: map[string][]data.DelegatedRole{
75 "targets": {
76 {Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs, Terminating: true},
77 {Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
78 },
79 "b": {
80 {Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
81 {Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
82 },
83 },
84 file: "",
85 resultOrder: []string{"targets", "b", "c", "d"},
86 },
87 {
88 testName: "path does not match b",
89 roles: map[string][]data.DelegatedRole{
90 "targets": {
91 {Name: "b", Paths: noMatchPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
92 {Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
93 },
94 "b": {
95 {Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
96 {Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
97 },
98 },
99 file: "",
100 resultOrder: []string{"targets", "e"},
101 },
102 {
103 testName: "path does not match b - path prefixes",
104 roles: map[string][]data.DelegatedRole{
105 "targets": {
106 {Name: "b", PathHashPrefixes: []string{"33472a4909"}, Threshold: 1, KeyIDs: defaultKeyIDs},
107 {Name: "c", PathHashPrefixes: []string{"34c85d1ee84f61f10d7dc633"}, Threshold: 1, KeyIDs: defaultKeyIDs},
108 },
109 "c": {
110
111 {Name: "d", PathHashPrefixes: []string{"8baf"}, Threshold: 1, KeyIDs: defaultKeyIDs},
112 {Name: "e", PathHashPrefixes: []string{"34c85d1ee84f61f10d7dc633472a49096ed87f8f764bd597831eac371f40ac39"}, Threshold: 1, KeyIDs: defaultKeyIDs},
113 },
114 },
115 file: "/e/f/g.txt",
116 resultOrder: []string{"targets", "c", "e"},
117 },
118 {
119 testName: "err paths and pathHashPrefixes are set",
120 roles: map[string][]data.DelegatedRole{
121 "targets": {
122 {Name: "b", Paths: defaultPathPatterns, PathHashPrefixes: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
123 },
124 "b": {},
125 },
126 file: "",
127 resultOrder: []string{"targets"},
128 err: data.ErrPathsAndPathHashesSet,
129 },
130 {
131 testName: "cycle avoided 1",
132 roles: map[string][]data.DelegatedRole{
133 "targets": {
134 {Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
135 },
136 "a": {
137 {Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
138 {Name: "e", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
139 },
140 "b": {
141 {Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
142 {Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
143 },
144 },
145 file: "",
146 resultOrder: []string{"targets", "a", "b", "d", "e"},
147 },
148 {
149 testName: "cycle avoided 2",
150 roles: map[string][]data.DelegatedRole{
151 "targets": {
152 {Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
153 },
154 "a": {
155 {Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
156 {Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
157 },
158 "b": {
159 {Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
160 {Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
161 {Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
162 },
163 "c": {
164 {Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
165 },
166 },
167 file: "",
168 resultOrder: []string{"targets", "a", "b", "c"},
169 },
170 {
171 testName: "diamond delegation",
172 roles: map[string][]data.DelegatedRole{
173 "targets": {
174 {Name: "b", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
175 {Name: "c", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
176 },
177 "b": {
178 {Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
179 },
180 "c": {
181 {Name: "d", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
182 },
183 },
184 file: "",
185 resultOrder: []string{"targets", "b", "d", "c"},
186 },
187 {
188 testName: "simple cycle",
189 roles: map[string][]data.DelegatedRole{
190 "targets": {
191 {Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
192 },
193 "a": {
194 {Name: "a", Paths: defaultPathPatterns, Threshold: 1, KeyIDs: defaultKeyIDs},
195 },
196 },
197 file: "",
198 resultOrder: []string{"targets", "a"},
199 },
200 }
201
202 for _, tt := range iteratorTests {
203 t.Run(tt.testName, func(t *testing.T) {
204 topLevelDB := verify.NewDB()
205 topLevelDB.AddKey(topTargetsPubKey.IDs()[0], topTargetsPubKey)
206 topLevelDB.AddRole("targets", &data.Role{
207 KeyIDs: topTargetsPubKey.IDs(),
208 Threshold: 1,
209 })
210
211 d, err := NewDelegationsIterator(tt.file, topLevelDB)
212 assert.NoError(t, err)
213
214 var iterationOrder []string
215 for {
216 r, ok := d.Next()
217 if !ok {
218 break
219 }
220
221
222
223
224 assert.Greater(t, len(r.Delegatee.KeyIDs), 0)
225
226 iterationOrder = append(iterationOrder, r.Delegatee.Name)
227 delegations, ok := tt.roles[r.Delegatee.Name]
228 if !ok {
229 continue
230 }
231
232 db, err := verify.NewDBFromDelegations(&data.Delegations{
233 Roles: delegations,
234 })
235 assert.NoError(t, err)
236
237 err = d.Add(delegations, r.Delegatee.Name, db)
238 assert.Equal(t, tt.err, err)
239 }
240 assert.Equal(t, tt.resultOrder, iterationOrder)
241 })
242 }
243 }
244
245 func TestNewDelegationsIteratorError(t *testing.T) {
246
247
248 tldb := verify.NewDB()
249
250 _, err := NewDelegationsIterator("targets", tldb)
251 assert.ErrorIs(t, err, ErrTopLevelTargetsRoleMissing)
252 }
253
View as plain text