1 package data
2
3 import (
4 "encoding/json"
5 "testing"
6
7 "github.com/secure-systems-lab/go-securesystemslib/cjson"
8 "github.com/stretchr/testify/assert"
9 . "gopkg.in/check.v1"
10 )
11
12 const (
13
14
15
16
17 public = `"72378e5bc588793e58f81c8533da64a2e8f1565c1fcc7f253496394ffc52542c"`
18 keyid10 = "1bf1c6e3cdd3d3a8420b19199e27511999850f4b376c4547b2f32fba7e80fca3"
19 keyid10algos = "506a349b85945d0d99c7289c3f0f1f6c550218089d1d38a3f64824db31e827ac"
20 )
21
22 type TypesSuite struct{}
23
24 var _ = Suite(&TypesSuite{})
25
26 type ed25519Public struct {
27 PublicKey HexBytes `json:"public"`
28 }
29
30 func (TypesSuite) TestKeyIDs(c *C) {
31 var hexbytes HexBytes
32 err := json.Unmarshal([]byte(public), &hexbytes)
33 c.Assert(err, IsNil)
34 keyValBytes, err := json.Marshal(ed25519Public{PublicKey: hexbytes})
35 c.Assert(err, IsNil)
36
37 key := PublicKey{
38 Type: KeyTypeEd25519,
39 Scheme: KeySchemeEd25519,
40 Value: keyValBytes,
41 }
42 c.Assert(key.IDs(), DeepEquals, []string{keyid10})
43
44 key = PublicKey{
45 Type: KeyTypeEd25519,
46 Scheme: KeySchemeEd25519,
47 Algorithms: HashAlgorithms,
48 Value: keyValBytes,
49 }
50 c.Assert(key.IDs(), DeepEquals, []string{keyid10algos})
51 }
52
53 func (TypesSuite) TestRootAddKey(c *C) {
54 var hexbytes HexBytes
55 err := json.Unmarshal([]byte(public), &hexbytes)
56 c.Assert(err, IsNil)
57 keyValBytes, err := json.Marshal(ed25519Public{PublicKey: hexbytes})
58 c.Assert(err, IsNil)
59
60 key := &PublicKey{
61 Type: KeyTypeEd25519,
62 Scheme: KeySchemeEd25519,
63 Value: keyValBytes,
64 }
65
66 root := NewRoot()
67
68 c.Assert(root.AddKey(key), Equals, true)
69 c.Assert(root.AddKey(key), Equals, false)
70 }
71
72 func (TypesSuite) TestRoleAddKeyIDs(c *C) {
73 var hexbytes HexBytes
74 err := json.Unmarshal([]byte(public), &hexbytes)
75 c.Assert(err, IsNil)
76 keyValBytes, err := json.Marshal(ed25519Public{PublicKey: hexbytes})
77 c.Assert(err, IsNil)
78
79 key := &PublicKey{
80 Type: KeyTypeEd25519,
81 Scheme: KeySchemeEd25519,
82 Value: keyValBytes,
83 }
84
85 role := &Role{}
86 c.Assert(role.KeyIDs, HasLen, 0)
87
88 c.Assert(role.AddKeyIDs(key.IDs()), Equals, true)
89 c.Assert(role.KeyIDs, DeepEquals, []string{keyid10})
90
91
92 c.Assert(role.AddKeyIDs(key.IDs()), Equals, false)
93 c.Assert(role.KeyIDs, DeepEquals, []string{keyid10})
94
95
96 key = &PublicKey{
97 Type: KeyTypeEd25519,
98 Scheme: KeySchemeEd25519,
99 Algorithms: HashAlgorithms,
100 Value: keyValBytes,
101 }
102
103
104 c.Assert(role.AddKeyIDs(key.IDs()), Equals, true)
105 c.Assert(role.KeyIDs, DeepEquals, []string{keyid10, keyid10algos})
106 }
107
108 func TestDelegatedRolePathMatch(t *testing.T) {
109 var tts = []struct {
110 testName string
111 pathPatterns []string
112 pathHashPrefixes []string
113 file string
114 shouldMatch bool
115 }{
116 {
117 testName: "no path",
118 file: "licence.txt",
119 },
120 {
121 testName: "match path *",
122 pathPatterns: []string{"null", "targets/*.tgz"},
123 file: "targets/foo.tgz",
124 shouldMatch: true,
125 },
126 {
127 testName: "does not match path *",
128 pathPatterns: []string{"null", "targets/*.tgz"},
129 file: "targets/foo.txt",
130 shouldMatch: false,
131 },
132 {
133 testName: "match path ?",
134 pathPatterns: []string{"foo-version-?.tgz"},
135 file: "foo-version-a.tgz",
136 shouldMatch: true,
137 },
138 {
139 testName: "does not match ?",
140 pathPatterns: []string{"foo-version-?.tgz"},
141 file: "foo-version-alpha.tgz",
142 shouldMatch: false,
143 },
144
145 {
146 testName: "match hash prefix",
147 pathHashPrefixes: []string{"badd", "8baf"},
148 file: "/file3.txt",
149 shouldMatch: true,
150 },
151 {
152 testName: "does not match hash prefix",
153 pathHashPrefixes: []string{"badd"},
154 file: "/file3.txt",
155 shouldMatch: false,
156 },
157 {
158 testName: "hash prefix first char",
159 pathHashPrefixes: []string{"2"},
160 file: "/a/b/c/file_d.txt",
161 shouldMatch: true,
162 },
163 {
164 testName: "full hash prefix",
165 pathHashPrefixes: []string{"34c85d1ee84f61f10d7dc633472a49096ed87f8f764bd597831eac371f40ac39"},
166 file: "/e/f/g.txt",
167 shouldMatch: true,
168 },
169 }
170 for _, tt := range tts {
171 t.Run(tt.testName, func(t *testing.T) {
172 d := DelegatedRole{
173 Paths: tt.pathPatterns,
174 PathHashPrefixes: tt.pathHashPrefixes,
175 }
176 assert.NoError(t, d.validatePaths())
177
178 matchesPath, err := d.MatchesPath(tt.file)
179 assert.NoError(t, err)
180 assert.Equal(t, tt.shouldMatch, matchesPath)
181 })
182
183 }
184 }
185
186 func TestDelegatedRoleJSON(t *testing.T) {
187 var tts = []struct {
188 testName string
189 d *DelegatedRole
190 rawCJSON string
191 }{{
192 testName: "all fields with hashes",
193 d: &DelegatedRole{
194 Name: "n1",
195 KeyIDs: []string{"k1"},
196 Threshold: 5,
197 Terminating: true,
198 PathHashPrefixes: []string{"8f"},
199 },
200 rawCJSON: `{"keyids":["k1"],"name":"n1","path_hash_prefixes":["8f"],"paths":null,"terminating":true,"threshold":5}`,
201 },
202 {
203 testName: "paths only",
204 d: &DelegatedRole{
205 Name: "n2",
206 KeyIDs: []string{"k1", "k3"},
207 Threshold: 12,
208 Paths: []string{"*.txt"},
209 },
210 rawCJSON: `{"keyids":["k1","k3"],"name":"n2","paths":["*.txt"],"terminating":false,"threshold":12}`,
211 },
212 {
213 testName: "default",
214 d: &DelegatedRole{},
215 rawCJSON: `{"keyids":null,"name":"","paths":null,"terminating":false,"threshold":0}`,
216 },
217 }
218
219 for _, tt := range tts {
220 t.Run(tt.testName, func(t *testing.T) {
221 b, err := cjson.EncodeCanonical(tt.d)
222 assert.NoError(t, err)
223 assert.Equal(t, tt.rawCJSON, string(b))
224
225 newD := &DelegatedRole{}
226 err = json.Unmarshal(b, newD)
227 assert.NoError(t, err)
228 assert.Equal(t, tt.d, newD)
229 })
230 }
231 }
232
233 func TestDelegatedRoleUnmarshalErr(t *testing.T) {
234 targetsWithBothMatchers := []byte(`{"keyids":null,"name":"","paths":["*.txt"],"path_hash_prefixes":["8f"],"terminating":false,"threshold":0}`)
235 var d DelegatedRole
236 assert.Equal(t, ErrPathsAndPathHashesSet, json.Unmarshal(targetsWithBothMatchers, &d))
237
238
239 err := json.Unmarshal([]byte(`{"keyids":"a"}`), &d)
240 assert.Equal(t, "keyids", err.(*json.UnmarshalTypeError).Field)
241 }
242
243 func TestCustomField(t *testing.T) {
244 testCustomJSON := json.RawMessage([]byte(`{"test":true}`))
245
246 root := Root{
247 Type: "root",
248 SpecVersion: "1.0",
249 Keys: make(map[string]*PublicKey),
250 Roles: make(map[string]*Role),
251 ConsistentSnapshot: true,
252 Custom: &testCustomJSON,
253 }
254 rootJSON, err := json.Marshal(&root)
255 assert.NoError(t, err)
256 assert.Equal(t, []byte("{\"_type\":\"root\",\"spec_version\":\"1.0\",\"version\":0,\"expires\":\"0001-01-01T00:00:00Z\",\"keys\":{},\"roles\":{},\"custom\":{\"test\":true},\"consistent_snapshot\":true}"), rootJSON)
257
258 targets := Targets{
259 Type: "targets",
260 SpecVersion: "1.0",
261 Targets: make(TargetFiles),
262 Custom: &testCustomJSON,
263 }
264 targetsJSON, err := json.Marshal(&targets)
265 assert.NoError(t, err)
266 assert.Equal(t, []byte("{\"_type\":\"targets\",\"spec_version\":\"1.0\",\"version\":0,\"expires\":\"0001-01-01T00:00:00Z\",\"targets\":{},\"custom\":{\"test\":true}}"), targetsJSON)
267
268 snapshot := Snapshot{
269 Type: "snapshot",
270 SpecVersion: "1.0",
271 Meta: make(SnapshotFiles),
272 Custom: &testCustomJSON,
273 }
274 snapshotJSON, err := json.Marshal(&snapshot)
275 assert.NoError(t, err)
276 assert.Equal(t, []byte("{\"_type\":\"snapshot\",\"spec_version\":\"1.0\",\"version\":0,\"expires\":\"0001-01-01T00:00:00Z\",\"meta\":{},\"custom\":{\"test\":true}}"), snapshotJSON)
277
278 timestamp := Timestamp{
279 Type: "timestamp",
280 SpecVersion: "1.0",
281 Meta: make(TimestampFiles),
282 Custom: &testCustomJSON,
283 }
284 timestampJSON, err := json.Marshal(×tamp)
285 assert.NoError(t, err)
286 assert.Equal(t, []byte("{\"_type\":\"timestamp\",\"spec_version\":\"1.0\",\"version\":0,\"expires\":\"0001-01-01T00:00:00Z\",\"meta\":{},\"custom\":{\"test\":true}}"), timestampJSON)
287 }
288
View as plain text