1 package in_toto
2
3 import (
4 "encoding/json"
5 "testing"
6 "time"
7
8 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common"
9 slsa01 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1"
10 slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
11 "github.com/stretchr/testify/assert"
12 )
13
14 func TestDecodeProvenanceStatementSLSA02(t *testing.T) {
15
16
17 var data = `
18 {
19 "_type": "https://in-toto.io/Statement/v0.1",
20 "subject": [
21 { "name": "curl-7.72.0.tar.bz2",
22 "digest": { "sha256": "ad91970864102a59765e20ce16216efc9d6ad381471f7accceceab7d905703ef" }},
23 { "name": "curl-7.72.0.tar.gz",
24 "digest": { "sha256": "d4d5899a3868fbb6ae1856c3e55a32ce35913de3956d1973caccd37bd0174fa2" }}
25 ],
26 "predicateType": "https://slsa.dev/provenance/v0.2",
27 "predicate": {
28 "builder": { "id": "https://github.com/Attestations/GitHubHostedActions@v1" },
29 "buildType": "https://github.com/Attestations/GitHubActionsWorkflow@v1",
30 "invocation": {
31 "configSource": {
32 "uri": "git+https://github.com/curl/curl-docker@master",
33 "digest": { "sha1": "d6525c840a62b398424a78d792f457477135d0cf" },
34 "entryPoint": "build.yaml:maketgz"
35 }
36 },
37 "metadata": {
38 "buildStartedOn": "2020-08-19T08:38:00Z",
39 "completeness": {
40 "environment": true
41 }
42 },
43 "materials": [
44 {
45 "uri": "git+https://github.com/curl/curl-docker@master",
46 "digest": { "sha1": "d6525c840a62b398424a78d792f457477135d0cf" }
47 }, {
48 "uri": "github_hosted_vm:ubuntu-18.04:20210123.1"
49 }
50 ]
51 }
52 }
53 `
54
55 var testTime = time.Unix(1597826280, 0)
56 var want = ProvenanceStatement{
57 StatementHeader: StatementHeader{
58 Type: StatementInTotoV01,
59 PredicateType: slsa02.PredicateSLSAProvenance,
60 Subject: []Subject{
61 {
62 Name: "curl-7.72.0.tar.bz2",
63 Digest: common.DigestSet{
64 "sha256": "ad91970864102a59765e20ce16216efc9d6ad381471f7accceceab7d905703ef",
65 },
66 },
67 {
68 Name: "curl-7.72.0.tar.gz",
69 Digest: common.DigestSet{
70 "sha256": "d4d5899a3868fbb6ae1856c3e55a32ce35913de3956d1973caccd37bd0174fa2",
71 },
72 },
73 },
74 },
75 Predicate: slsa02.ProvenancePredicate{
76 Builder: common.ProvenanceBuilder{
77 ID: "https://github.com/Attestations/GitHubHostedActions@v1",
78 },
79 BuildType: "https://github.com/Attestations/GitHubActionsWorkflow@v1",
80 Invocation: slsa02.ProvenanceInvocation{
81 ConfigSource: slsa02.ConfigSource{
82 EntryPoint: "build.yaml:maketgz",
83 URI: "git+https://github.com/curl/curl-docker@master",
84 Digest: common.DigestSet{
85 "sha1": "d6525c840a62b398424a78d792f457477135d0cf",
86 },
87 },
88 },
89 Metadata: &slsa02.ProvenanceMetadata{
90 BuildStartedOn: &testTime,
91 Completeness: slsa02.ProvenanceComplete{
92 Environment: true,
93 },
94 },
95 Materials: []common.ProvenanceMaterial{
96 {
97 URI: "git+https://github.com/curl/curl-docker@master",
98 Digest: common.DigestSet{
99 "sha1": "d6525c840a62b398424a78d792f457477135d0cf",
100 },
101 },
102 {
103 URI: "github_hosted_vm:ubuntu-18.04:20210123.1",
104 },
105 },
106 },
107 }
108 var got ProvenanceStatement
109
110 if err := json.Unmarshal([]byte(data), &got); err != nil {
111 t.Errorf("failed to unmarshal json: %s\n", err)
112 return
113 }
114
115
116
117 loc := want.Predicate.Metadata.BuildStartedOn.Location()
118 tmp := got.Predicate.Metadata.BuildStartedOn.In(loc)
119 got.Predicate.Metadata.BuildStartedOn = &tmp
120
121 assert.Equal(t, want, got, "Unexpexted object after decoding")
122 }
123
124 func TestEncodeProvenanceStatementSLSA02(t *testing.T) {
125 var testTime = time.Unix(1597826280, 0)
126 var p = ProvenanceStatement{
127 StatementHeader: StatementHeader{
128 Type: StatementInTotoV01,
129 PredicateType: slsa02.PredicateSLSAProvenance,
130 Subject: []Subject{
131 {
132 Name: "curl-7.72.0.tar.bz2",
133 Digest: common.DigestSet{
134 "sha256": "ad91970864102a59765e20ce16216efc9d6ad381471f7accceceab7d905703ef",
135 },
136 },
137 {
138 Name: "curl-7.72.0.tar.gz",
139 Digest: common.DigestSet{
140 "sha256": "d4d5899a3868fbb6ae1856c3e55a32ce35913de3956d1973caccd37bd0174fa2",
141 },
142 },
143 },
144 },
145 Predicate: slsa02.ProvenancePredicate{
146 Builder: common.ProvenanceBuilder{
147 ID: "https://github.com/Attestations/GitHubHostedActions@v1",
148 },
149 BuildType: "https://github.com/Attestations/GitHubActionsWorkflow@v1",
150 Invocation: slsa02.ProvenanceInvocation{
151 ConfigSource: slsa02.ConfigSource{
152 URI: "git+https://github.com/curl/curl-docker@master",
153 Digest: common.DigestSet{
154 "sha1": "d6525c840a62b398424a78d792f457477135d0cf",
155 },
156 EntryPoint: "build.yaml:maketgz",
157 },
158 },
159 Metadata: &slsa02.ProvenanceMetadata{
160 BuildStartedOn: &testTime,
161 BuildFinishedOn: &testTime,
162 Completeness: slsa02.ProvenanceComplete{
163 Parameters: true,
164 Environment: false,
165 Materials: true,
166 },
167 },
168 Materials: []common.ProvenanceMaterial{
169 {
170 URI: "git+https://github.com/curl/curl-docker@master",
171 Digest: common.DigestSet{
172 "sha1": "d6525c840a62b398424a78d792f457477135d0cf",
173 },
174 },
175 {
176 URI: "github_hosted_vm:ubuntu-18.04:20210123.1",
177 },
178 {
179 URI: "git+https://github.com/curl/",
180 },
181 },
182 },
183 }
184 var want = `{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"curl-7.72.0.tar.bz2","digest":{"sha256":"ad91970864102a59765e20ce16216efc9d6ad381471f7accceceab7d905703ef"}},{"name":"curl-7.72.0.tar.gz","digest":{"sha256":"d4d5899a3868fbb6ae1856c3e55a32ce35913de3956d1973caccd37bd0174fa2"}}],"predicate":{"builder":{"id":"https://github.com/Attestations/GitHubHostedActions@v1"},"buildType":"https://github.com/Attestations/GitHubActionsWorkflow@v1","invocation":{"configSource":{"uri":"git+https://github.com/curl/curl-docker@master","digest":{"sha1":"d6525c840a62b398424a78d792f457477135d0cf"},"entryPoint":"build.yaml:maketgz"}},"metadata":{"buildStartedOn":"2020-08-19T08:38:00Z","buildFinishedOn":"2020-08-19T08:38:00Z","completeness":{"parameters":true,"environment":false,"materials":true},"reproducible":false},"materials":[{"uri":"git+https://github.com/curl/curl-docker@master","digest":{"sha1":"d6525c840a62b398424a78d792f457477135d0cf"}},{"uri":"github_hosted_vm:ubuntu-18.04:20210123.1"},{"uri":"git+https://github.com/curl/"}]}}`
185
186 b, err := json.Marshal(&p)
187 assert.Nil(t, err, "Error during JSON marshal")
188 assert.Equal(t, want, string(b), "Wrong JSON produced")
189 }
190
191 func TestDecodeProvenanceStatementSLSA01(t *testing.T) {
192
193
194 var data = `
195 {
196 "_type": "https://in-toto.io/Statement/v0.1",
197 "subject": [
198 { "name": "curl-7.72.0.tar.bz2",
199 "digest": { "sha256": "ad91970864102a59765e20ce16216efc9d6ad381471f7accceceab7d905703ef" }},
200 { "name": "curl-7.72.0.tar.gz",
201 "digest": { "sha256": "d4d5899a3868fbb6ae1856c3e55a32ce35913de3956d1973caccd37bd0174fa2" }}
202 ],
203 "predicateType": "https://slsa.dev/provenance/v0.1",
204 "predicate": {
205 "builder": { "id": "https://github.com/Attestations/GitHubHostedActions@v1" },
206 "recipe": {
207 "type": "https://github.com/Attestations/GitHubActionsWorkflow@v1",
208 "definedInMaterial": 0,
209 "entryPoint": "build.yaml:maketgz"
210 },
211 "metadata": {
212 "buildStartedOn": "2020-08-19T08:38:00Z",
213 "completeness": {
214 "environment": true
215 }
216 },
217 "materials": [
218 {
219 "uri": "git+https://github.com/curl/curl-docker@master",
220 "digest": { "sha1": "d6525c840a62b398424a78d792f457477135d0cf" }
221 }, {
222 "uri": "github_hosted_vm:ubuntu-18.04:20210123.1"
223 }
224 ]
225 }
226 }
227 `
228
229 var testTime = time.Unix(1597826280, 0)
230 var want = ProvenanceStatementSLSA01{
231 StatementHeader: StatementHeader{
232 Type: StatementInTotoV01,
233 PredicateType: slsa01.PredicateSLSAProvenance,
234 Subject: []Subject{
235 {
236 Name: "curl-7.72.0.tar.bz2",
237 Digest: common.DigestSet{
238 "sha256": "ad91970864102a59765e20ce16216efc9d6ad381471f7accceceab7d905703ef",
239 },
240 },
241 {
242 Name: "curl-7.72.0.tar.gz",
243 Digest: common.DigestSet{
244 "sha256": "d4d5899a3868fbb6ae1856c3e55a32ce35913de3956d1973caccd37bd0174fa2",
245 },
246 },
247 },
248 },
249 Predicate: slsa01.ProvenancePredicate{
250 Builder: common.ProvenanceBuilder{
251 ID: "https://github.com/Attestations/GitHubHostedActions@v1",
252 },
253 Recipe: slsa01.ProvenanceRecipe{
254 Type: "https://github.com/Attestations/GitHubActionsWorkflow@v1",
255 DefinedInMaterial: new(int),
256 EntryPoint: "build.yaml:maketgz",
257 },
258 Metadata: &slsa01.ProvenanceMetadata{
259 BuildStartedOn: &testTime,
260 Completeness: slsa01.ProvenanceComplete{
261 Environment: true,
262 },
263 },
264 Materials: []common.ProvenanceMaterial{
265 {
266 URI: "git+https://github.com/curl/curl-docker@master",
267 Digest: common.DigestSet{
268 "sha1": "d6525c840a62b398424a78d792f457477135d0cf",
269 },
270 },
271 {
272 URI: "github_hosted_vm:ubuntu-18.04:20210123.1",
273 },
274 },
275 },
276 }
277 var got ProvenanceStatementSLSA01
278
279 if err := json.Unmarshal([]byte(data), &got); err != nil {
280 t.Errorf("failed to unmarshal json: %s\n", err)
281 return
282 }
283
284
285
286 loc := want.Predicate.Metadata.BuildStartedOn.Location()
287 tmp := got.Predicate.Metadata.BuildStartedOn.In(loc)
288 got.Predicate.Metadata.BuildStartedOn = &tmp
289
290 assert.Equal(t, want, got, "Unexpexted object after decoding")
291 }
292
293 func TestEncodeProvenanceStatementSLSA01(t *testing.T) {
294 var testTime = time.Unix(1597826280, 0)
295 var p = ProvenanceStatementSLSA01{
296 StatementHeader: StatementHeader{
297 Type: StatementInTotoV01,
298 PredicateType: slsa01.PredicateSLSAProvenance,
299 Subject: []Subject{
300 {
301 Name: "curl-7.72.0.tar.bz2",
302 Digest: common.DigestSet{
303 "sha256": "ad91970864102a59765e20ce16216efc9d6ad381471f7accceceab7d905703ef",
304 },
305 },
306 {
307 Name: "curl-7.72.0.tar.gz",
308 Digest: common.DigestSet{
309 "sha256": "d4d5899a3868fbb6ae1856c3e55a32ce35913de3956d1973caccd37bd0174fa2",
310 },
311 },
312 },
313 },
314 Predicate: slsa01.ProvenancePredicate{
315 Builder: common.ProvenanceBuilder{
316 ID: "https://github.com/Attestations/GitHubHostedActions@v1",
317 },
318 Recipe: slsa01.ProvenanceRecipe{
319 Type: "https://github.com/Attestations/GitHubActionsWorkflow@v1",
320 DefinedInMaterial: new(int),
321 EntryPoint: "build.yaml:maketgz",
322 },
323 Metadata: &slsa01.ProvenanceMetadata{
324 BuildStartedOn: &testTime,
325 BuildFinishedOn: &testTime,
326 Completeness: slsa01.ProvenanceComplete{
327 Arguments: true,
328 Environment: false,
329 Materials: true,
330 },
331 },
332 Materials: []common.ProvenanceMaterial{
333 {
334 URI: "git+https://github.com/curl/curl-docker@master",
335 Digest: common.DigestSet{
336 "sha1": "d6525c840a62b398424a78d792f457477135d0cf",
337 },
338 },
339 {
340 URI: "github_hosted_vm:ubuntu-18.04:20210123.1",
341 },
342 {
343 URI: "git+https://github.com/curl/",
344 },
345 },
346 },
347 }
348 var want = `{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.1","subject":[{"name":"curl-7.72.0.tar.bz2","digest":{"sha256":"ad91970864102a59765e20ce16216efc9d6ad381471f7accceceab7d905703ef"}},{"name":"curl-7.72.0.tar.gz","digest":{"sha256":"d4d5899a3868fbb6ae1856c3e55a32ce35913de3956d1973caccd37bd0174fa2"}}],"predicate":{"builder":{"id":"https://github.com/Attestations/GitHubHostedActions@v1"},"recipe":{"type":"https://github.com/Attestations/GitHubActionsWorkflow@v1","definedInMaterial":0,"entryPoint":"build.yaml:maketgz"},"metadata":{"buildStartedOn":"2020-08-19T08:38:00Z","buildFinishedOn":"2020-08-19T08:38:00Z","completeness":{"arguments":true,"environment":false,"materials":true},"reproducible":false},"materials":[{"uri":"git+https://github.com/curl/curl-docker@master","digest":{"sha1":"d6525c840a62b398424a78d792f457477135d0cf"}},{"uri":"github_hosted_vm:ubuntu-18.04:20210123.1"},{"uri":"git+https://github.com/curl/"}]}}`
349
350 b, err := json.Marshal(&p)
351 assert.Nil(t, err, "Error during JSON marshal")
352 assert.Equal(t, want, string(b), "Wrong JSON produced")
353 }
354
355
356
357 func TestMetadataNoTime(t *testing.T) {
358 var md = slsa02.ProvenanceMetadata{
359 Completeness: slsa02.ProvenanceComplete{
360 Parameters: true,
361 },
362 Reproducible: true,
363 }
364 var want = `{"completeness":{"parameters":true,"environment":false,"materials":false},"reproducible":true}`
365 var got slsa02.ProvenanceMetadata
366 b, err := json.Marshal(&md)
367
368 t.Run("Marshal", func(t *testing.T) {
369 assert.Nil(t, err, "Error during JSON marshal")
370 assert.Equal(t, want, string(b), "Wrong JSON produced")
371 })
372
373 t.Run("Unmashal", func(t *testing.T) {
374 err := json.Unmarshal(b, &got)
375 assert.Nil(t, err, "Error during JSON unmarshal")
376 assert.Equal(t, md, got, "Wrong struct after JSON unmarshal")
377 })
378 }
379
380
381
382 func TestRecipe(t *testing.T) {
383 var r = slsa01.ProvenanceRecipe{
384 Type: "testType",
385 EntryPoint: "testEntry",
386 }
387 var want = `{"type":"testType","entryPoint":"testEntry"}`
388 var got slsa01.ProvenanceRecipe
389 b, err := json.Marshal(&r)
390
391 t.Run("No time/marshal", func(t *testing.T) {
392 assert.Nil(t, err, "Error during JSON marshal")
393 assert.Equal(t, want, string(b), "Wrong JSON produced")
394 })
395
396 t.Run("No time/unmarshal", func(t *testing.T) {
397 err = json.Unmarshal(b, &got)
398 assert.Nil(t, err, "Error during JSON unmarshal")
399 assert.Equal(t, r, got, "Wrong struct after JSON unmarshal")
400 })
401
402
403 r.DefinedInMaterial = new(int)
404 want = `{"type":"testType","definedInMaterial":0,"entryPoint":"testEntry"}`
405 b, err = json.Marshal(&r)
406
407 t.Run("With time/marshal", func(t *testing.T) {
408 assert.Nil(t, err, "Error during JSON marshal")
409 assert.Equal(t, want, string(b), "Wrong JSON produced")
410 })
411
412 t.Run("With time/unmarshal", func(t *testing.T) {
413 err = json.Unmarshal(b, &got)
414 assert.Nil(t, err, "Error during JSON unmarshal")
415 assert.Equal(t, r, got, "Wrong struct after JSON unmarshal")
416 })
417 }
418
419 func TestLinkStatement(t *testing.T) {
420 var data = `
421 {
422 "subject": [
423 {"name": "baz",
424 "digest": { "sha256": "hash1" }}
425 ],
426 "predicateType": "https://in-toto.io/Link/v1",
427 "predicate": {
428 "_type": "link",
429 "name": "name",
430 "command": ["cc", "-o", "baz", "baz.z"],
431 "materials": {
432 "kv": "vv"
433 },
434 "products": {
435 "kp": "vp"
436 },
437 "byproducts": {
438 "kb": "vb"
439 },
440 "environment": {
441 "FOO": "BAR"
442 }
443 }
444 }
445 `
446
447 var want = LinkStatement{
448 StatementHeader: StatementHeader{
449 PredicateType: PredicateLinkV1,
450 Subject: []Subject{
451 {
452 Name: "baz",
453 Digest: common.DigestSet{
454 "sha256": "hash1",
455 },
456 },
457 },
458 },
459 Predicate: Link{
460 Type: "link",
461 Name: "name",
462 Materials: map[string]interface{}{
463 "kv": "vv",
464 },
465 Products: map[string]interface{}{
466 "kp": "vp",
467 },
468 ByProducts: map[string]interface{}{
469 "kb": "vb",
470 },
471 Environment: map[string]interface{}{
472 "FOO": "BAR",
473 },
474 Command: []string{"cc", "-o", "baz", "baz.z"},
475 },
476 }
477 var got LinkStatement
478
479 if err := json.Unmarshal([]byte(data), &got); err != nil {
480 t.Errorf("failed to unmarshal json: %s\n", err)
481 return
482 }
483
484 assert.Equal(t, want, got, "Unexpexted object after decoding")
485 }
486
View as plain text