@@ -20,11 +20,13 @@ package attestation
2020
2121import (
2222 "crypto/x509"
23+ "encoding/json"
2324 "fmt"
2425 "testing"
2526
2627 "github.com/gkampitakis/go-snaps/snaps"
2728 "github.com/google/go-containerregistry/pkg/v1/types"
29+ "github.com/in-toto/in-toto-golang/in_toto"
2830 ct "github.com/sigstore/cosign/v2/pkg/types"
2931 "github.com/stretchr/testify/assert"
3032 "github.com/stretchr/testify/mock"
@@ -125,3 +127,248 @@ func TestProvenanceFromSignature(t *testing.T) {
125127 })
126128 }
127129}
130+
131+ func TestProvenance_Type (t * testing.T ) {
132+ tests := []struct {
133+ name string
134+ expected string
135+ }{
136+ {
137+ name : "returns correct in-toto statement type" ,
138+ expected : "https://in-toto.io/Statement/v0.1" ,
139+ },
140+ }
141+
142+ for _ , tt := range tests {
143+ t .Run (tt .name , func (t * testing.T ) {
144+ p := provenance {}
145+ result := p .Type ()
146+ assert .Equal (t , tt .expected , result )
147+ })
148+ }
149+ }
150+
151+ func TestProvenance_Statement (t * testing.T ) {
152+ tests := []struct {
153+ name string
154+ data []byte
155+ expected []byte
156+ }{
157+ {
158+ name : "returns stored data correctly" ,
159+ data : []byte (`{"test": "data"}` ),
160+ expected : []byte (`{"test": "data"}` ),
161+ },
162+ {
163+ name : "returns empty data when nil" ,
164+ data : nil ,
165+ expected : nil ,
166+ },
167+ {
168+ name : "returns empty data when empty slice" ,
169+ data : []byte {},
170+ expected : []byte {},
171+ },
172+ }
173+
174+ for _ , tt := range tests {
175+ t .Run (tt .name , func (t * testing.T ) {
176+ p := provenance {data : tt .data }
177+ result := p .Statement ()
178+ assert .Equal (t , tt .expected , result )
179+ })
180+ }
181+ }
182+
183+ func TestProvenance_Signatures (t * testing.T ) {
184+ mockSig1 := signature.EntitySignature {
185+ KeyID : "key1" ,
186+ Signature : "sig1" ,
187+ }
188+ mockSig2 := signature.EntitySignature {
189+ KeyID : "key2" ,
190+ Signature : "sig2" ,
191+ }
192+
193+ tests := []struct {
194+ name string
195+ signatures []signature.EntitySignature
196+ expected []signature.EntitySignature
197+ }{
198+ {
199+ name : "returns single signature" ,
200+ signatures : []signature.EntitySignature {mockSig1 },
201+ expected : []signature.EntitySignature {mockSig1 },
202+ },
203+ {
204+ name : "returns multiple signatures" ,
205+ signatures : []signature.EntitySignature {mockSig1 , mockSig2 },
206+ expected : []signature.EntitySignature {mockSig1 , mockSig2 },
207+ },
208+ {
209+ name : "returns empty slice when no signatures" ,
210+ signatures : []signature.EntitySignature {},
211+ expected : []signature.EntitySignature {},
212+ },
213+ }
214+
215+ for _ , tt := range tests {
216+ t .Run (tt .name , func (t * testing.T ) {
217+ p := provenance {signatures : tt .signatures }
218+ result := p .Signatures ()
219+ assert .Equal (t , tt .expected , result )
220+ })
221+ }
222+ }
223+
224+ func TestProvenance_Subject (t * testing.T ) {
225+ mockSubject1 := in_toto.Subject {
226+ Name : "subject1" ,
227+ Digest : map [string ]string {
228+ "sha256" : "digest1" ,
229+ },
230+ }
231+ mockSubject2 := in_toto.Subject {
232+ Name : "subject2" ,
233+ Digest : map [string ]string {
234+ "sha256" : "digest2" ,
235+ },
236+ }
237+
238+ tests := []struct {
239+ name string
240+ statement in_toto.Statement
241+ expected []in_toto.Subject
242+ }{
243+ {
244+ name : "returns single subject" ,
245+ statement : in_toto.Statement {
246+ StatementHeader : in_toto.StatementHeader {
247+ Subject : []in_toto.Subject {mockSubject1 },
248+ },
249+ },
250+ expected : []in_toto.Subject {mockSubject1 },
251+ },
252+ {
253+ name : "returns multiple subjects" ,
254+ statement : in_toto.Statement {
255+ StatementHeader : in_toto.StatementHeader {
256+ Subject : []in_toto.Subject {mockSubject1 , mockSubject2 },
257+ },
258+ },
259+ expected : []in_toto.Subject {mockSubject1 , mockSubject2 },
260+ },
261+ {
262+ name : "returns empty slice when no subjects" ,
263+ statement : in_toto.Statement {
264+ StatementHeader : in_toto.StatementHeader {
265+ Subject : []in_toto.Subject {},
266+ },
267+ },
268+ expected : []in_toto.Subject {},
269+ },
270+ }
271+
272+ for _ , tt := range tests {
273+ t .Run (tt .name , func (t * testing.T ) {
274+ p := provenance {statement : tt .statement }
275+ result := p .Subject ()
276+ assert .Equal (t , tt .expected , result )
277+ })
278+ }
279+ }
280+
281+ func TestProvenance_MarshalJSON (t * testing.T ) {
282+ mockSig1 := signature.EntitySignature {
283+ KeyID : "key1" ,
284+ Signature : "sig1" ,
285+ }
286+ mockSig2 := signature.EntitySignature {
287+ KeyID : "key2" ,
288+ Signature : "sig2" ,
289+ }
290+
291+ tests := []struct {
292+ name string
293+ provenance provenance
294+ expectedErr bool
295+ validate func (* testing.T , []byte )
296+ }{
297+ {
298+ name : "marshals successfully with single signature" ,
299+ provenance : provenance {
300+ statement : in_toto.Statement {
301+ StatementHeader : in_toto.StatementHeader {
302+ PredicateType : "https://example.com/predicate/v1" ,
303+ },
304+ },
305+ signatures : []signature.EntitySignature {mockSig1 },
306+ },
307+ expectedErr : false ,
308+ validate : func (t * testing.T , data []byte ) {
309+ var result map [string ]interface {}
310+ err := json .Unmarshal (data , & result )
311+ assert .NoError (t , err )
312+ assert .Equal (t , "https://in-toto.io/Statement/v0.1" , result ["type" ])
313+ assert .Equal (t , "https://example.com/predicate/v1" , result ["predicateType" ])
314+ assert .Len (t , result ["signatures" ], 1 )
315+ },
316+ },
317+ {
318+ name : "marshals successfully with multiple signatures" ,
319+ provenance : provenance {
320+ statement : in_toto.Statement {
321+ StatementHeader : in_toto.StatementHeader {
322+ PredicateType : "https://example.com/predicate/v2" ,
323+ },
324+ },
325+ signatures : []signature.EntitySignature {mockSig1 , mockSig2 },
326+ },
327+ expectedErr : false ,
328+ validate : func (t * testing.T , data []byte ) {
329+ var result map [string ]interface {}
330+ err := json .Unmarshal (data , & result )
331+ assert .NoError (t , err )
332+ assert .Equal (t , "https://in-toto.io/Statement/v0.1" , result ["type" ])
333+ assert .Equal (t , "https://example.com/predicate/v2" , result ["predicateType" ])
334+ assert .Len (t , result ["signatures" ], 2 )
335+ },
336+ },
337+ {
338+ name : "marshals successfully with empty signatures" ,
339+ provenance : provenance {
340+ statement : in_toto.Statement {
341+ StatementHeader : in_toto.StatementHeader {
342+ PredicateType : "https://example.com/predicate/v3" ,
343+ },
344+ },
345+ signatures : []signature.EntitySignature {},
346+ },
347+ expectedErr : false ,
348+ validate : func (t * testing.T , data []byte ) {
349+ var result map [string ]interface {}
350+ err := json .Unmarshal (data , & result )
351+ assert .NoError (t , err )
352+ assert .Equal (t , "https://in-toto.io/Statement/v0.1" , result ["type" ])
353+ assert .Equal (t , "https://example.com/predicate/v3" , result ["predicateType" ])
354+ assert .Len (t , result ["signatures" ], 0 )
355+ },
356+ },
357+ }
358+
359+ for _ , tt := range tests {
360+ t .Run (tt .name , func (t * testing.T ) {
361+ data , err := tt .provenance .MarshalJSON ()
362+
363+ if tt .expectedErr {
364+ assert .Error (t , err )
365+ return
366+ }
367+
368+ assert .NoError (t , err )
369+ if tt .validate != nil {
370+ tt .validate (t , data )
371+ }
372+ })
373+ }
374+ }
0 commit comments