@@ -15,7 +15,7 @@ limitations under the License.
1515*/
1616import type { SerializedBundle } from '@sigstore/bundle' ;
1717import { mockFulcio , mockRekor , mockTSA } from '@sigstore/mock' ;
18- import { VerificationError } from '@sigstore/verify' ;
18+ import { VerificationError , Signer } from '@sigstore/verify' ;
1919import { fromPartial } from '@total-typescript/shoehorn' ;
2020import mocktuf , { Target } from '@tufjs/repo-mock' ;
2121import { attest , createVerifier , sign , verify } from '../sigstore' ;
@@ -180,8 +180,12 @@ describe('#verify', () => {
180180 validBundles . v1 . dsse . withSigningCert
181181 ) ;
182182
183- it ( 'does not throw an error' , async ( ) => {
184- await expect ( verify ( bundle , tufOptions ) ) . resolves . toBe ( undefined ) ;
183+ it ( 'returns a Signer object' , async ( ) => {
184+ const result = await verify ( bundle , tufOptions ) ;
185+ expect ( result ) . toBeDefined ( ) ;
186+ expect ( result ) . toHaveProperty ( 'key' ) ;
187+ expect ( result . key ) . toBeDefined ( ) ;
188+ expect ( result ) . toHaveProperty ( 'identity' ) ;
185189 } , 10000 ) ;
186190 } ) ;
187191
@@ -196,8 +200,11 @@ describe('#verify', () => {
196200 timeout : 0 ,
197201 } ;
198202
199- it ( 'does not throw an error' , async ( ) => {
200- await expect ( verify ( bundle , options ) ) . resolves . toBe ( undefined ) ;
203+ it ( 'returns a Signer object' , async ( ) => {
204+ const result = await verify ( bundle , options ) ;
205+ expect ( result ) . toBeDefined ( ) ;
206+ expect ( result ) . toHaveProperty ( 'key' ) ;
207+ expect ( result . key ) . toBeDefined ( ) ;
201208 } ) ;
202209 } ) ;
203210
@@ -207,10 +214,12 @@ describe('#verify', () => {
207214 ) ;
208215 const artifact = validBundles . artifact ;
209216
210- it ( 'does not throw an error' , async ( ) => {
211- await expect ( verify ( bundle , artifact , tufOptions ) ) . resolves . toBe (
212- undefined
213- ) ;
217+ it ( 'returns a Signer object' , async ( ) => {
218+ const result = await verify ( bundle , artifact , tufOptions ) ;
219+ expect ( result ) . toBeDefined ( ) ;
220+ expect ( result ) . toHaveProperty ( 'key' ) ;
221+ expect ( result . key ) . toBeDefined ( ) ;
222+ expect ( result ) . toHaveProperty ( 'identity' ) ;
214223 } ) ;
215224 } ) ;
216225
@@ -220,10 +229,12 @@ describe('#verify', () => {
220229 ) ;
221230 const artifact = validBundles . artifact ;
222231
223- it ( 'does not throw an error' , async ( ) => {
224- await expect ( verify ( bundle , artifact , tufOptions ) ) . resolves . toBe (
225- undefined
226- ) ;
232+ it ( 'returns a Signer object' , async ( ) => {
233+ const result = await verify ( bundle , artifact , tufOptions ) ;
234+ expect ( result ) . toBeDefined ( ) ;
235+ expect ( result ) . toHaveProperty ( 'key' ) ;
236+ expect ( result . key ) . toBeDefined ( ) ;
237+ expect ( result ) . toHaveProperty ( 'identity' ) ;
227238 } ) ;
228239 } ) ;
229240
@@ -233,10 +244,12 @@ describe('#verify', () => {
233244 ) ;
234245 const artifact = validBundles . artifact ;
235246
236- it ( 'does not throw an error' , async ( ) => {
237- await expect ( verify ( bundle , artifact , tufOptions ) ) . resolves . toBe (
238- undefined
239- ) ;
247+ it ( 'returns a Signer object' , async ( ) => {
248+ const result = await verify ( bundle , artifact , tufOptions ) ;
249+ expect ( result ) . toBeDefined ( ) ;
250+ expect ( result ) . toHaveProperty ( 'key' ) ;
251+ expect ( result . key ) . toBeDefined ( ) ;
252+ expect ( result ) . toHaveProperty ( 'identity' ) ;
240253 } ) ;
241254 } ) ;
242255
@@ -246,10 +259,12 @@ describe('#verify', () => {
246259 ) ;
247260 const artifact = validBundles . artifact ;
248261
249- it ( 'does not throw an error' , async ( ) => {
250- await expect ( verify ( bundle , artifact , tufOptions ) ) . resolves . toBe (
251- undefined
252- ) ;
262+ it ( 'returns a Signer object' , async ( ) => {
263+ const result = await verify ( bundle , artifact , tufOptions ) ;
264+ expect ( result ) . toBeDefined ( ) ;
265+ expect ( result ) . toHaveProperty ( 'key' ) ;
266+ expect ( result . key ) . toBeDefined ( ) ;
267+ expect ( result ) . toHaveProperty ( 'identity' ) ;
253268 } ) ;
254269 } ) ;
255270
@@ -288,10 +303,107 @@ describe('#verify', () => {
288303
289304 const artifact = validBundles . artifact ;
290305
291- it ( 'does not throw an error' , async ( ) => {
292- await expect ( verify ( bundle , artifact , tufOptions ) ) . resolves . toBe (
293- undefined
294- ) ;
306+ it ( 'returns a Signer object' , async ( ) => {
307+ const result = await verify ( bundle , artifact , tufOptions ) ;
308+ expect ( result ) . toBeDefined ( ) ;
309+ expect ( result ) . toHaveProperty ( 'key' ) ;
310+ expect ( result . key ) . toBeDefined ( ) ;
311+ expect ( result ) . toHaveProperty ( 'identity' ) ;
312+ } ) ;
313+ } ) ;
314+ } ) ;
315+
316+ describe ( '#verify - Signer object structure and properties' , ( ) => {
317+ let tufRepo : ReturnType < typeof mocktuf > | undefined ;
318+ let tufOptions : VerifyOptions | undefined ;
319+
320+ const trustedRootJSON = JSON . stringify ( trustedRoot ) ;
321+ const target : Target = {
322+ name : 'trusted_root.json' ,
323+ content : Buffer . from ( trustedRootJSON ) ,
324+ } ;
325+
326+ beforeEach ( ( ) => {
327+ tufRepo = mocktuf ( target , { metadataPathPrefix : '' } ) ;
328+ tufOptions = {
329+ tufMirrorURL : tufRepo . baseURL ,
330+ tufCachePath : tufRepo . cachePath ,
331+ tufRootPath : path . join ( tufRepo . cachePath , 'root.json' ) ,
332+ certificateIssuer : 'https://github.com/login/oauth' ,
333+ } ;
334+ } ) ;
335+
336+ afterEach ( ( ) => tufRepo ?. teardown ( ) ) ;
337+
338+ describe ( 'when verifying a DSSE bundle with certificate' , ( ) => {
339+ const bundle : SerializedBundle = fromPartial (
340+ validBundles . v1 . dsse . withSigningCert
341+ ) ;
342+
343+ it ( 'returns a Signer with a valid key object' , async ( ) => {
344+ const result = await verify ( bundle , tufOptions ) ;
345+ expect ( result ) . toMatchObject ( {
346+ key : expect . any ( Object ) ,
347+ identity : expect . any ( Object ) ,
348+ } ) ;
349+
350+ // Verify the key is a proper crypto.KeyObject
351+ expect ( result . key ) . toHaveProperty ( 'asymmetricKeyType' ) ;
352+ expect ( typeof result . key . export ) . toBe ( 'function' ) ;
353+ } ) ;
354+
355+ it ( 'returns a Signer with certificate identity information' , async ( ) => {
356+ const result = await verify ( bundle , tufOptions ) ;
357+ expect ( result . identity ) . toBeDefined ( ) ;
358+
359+ // The identity should have either subjectAlternativeName or extensions
360+ expect (
361+ result . identity ?. subjectAlternativeName ||
362+ result . identity ?. extensions
363+ ) . toBeDefined ( ) ;
364+ } ) ;
365+
366+ } ) ;
367+
368+ describe ( 'when verifying a message signature bundle' , ( ) => {
369+ const bundle : SerializedBundle = fromPartial (
370+ validBundles . v1 . messageSignature . withSigningCert
371+ ) ;
372+ const artifact = validBundles . artifact ;
373+
374+ it ( 'returns a Signer object with key and identity' , async ( ) => {
375+ const result = await verify ( bundle , artifact , tufOptions ) ;
376+
377+ expect ( result ) . toMatchObject ( {
378+ key : expect . any ( Object ) ,
379+ identity : expect . any ( Object ) ,
380+ } ) ;
381+ } ) ;
382+
383+ it ( 'returns a key that can be used for cryptographic operations' , async ( ) => {
384+ const result = await verify ( bundle , artifact , tufOptions ) ;
385+
386+ // Verify we can export the public key
387+ expect ( ( ) => {
388+ result . key . export ( { format : 'pem' , type : 'spki' } ) ;
389+ } ) . not . toThrow ( ) ;
390+ } ) ;
391+ } ) ;
392+
393+ describe ( 'when verifying with public key' , ( ) => {
394+ const bundle : SerializedBundle = fromPartial (
395+ validBundles . v1 . dsse . withPublicKey
396+ ) ;
397+ const options : VerifyOptions = {
398+ ...tufOptions ,
399+ keySelector : ( hint : string ) => validBundles . publicKeys [ hint ] ,
400+ } ;
401+
402+ it ( 'returns a Signer with key' , async ( ) => {
403+ const result = await verify ( bundle , options ) ;
404+
405+ expect ( result ) . toHaveProperty ( 'key' ) ;
406+ expect ( result . key ) . toBeDefined ( ) ;
295407 } ) ;
296408 } ) ;
297409} ) ;
@@ -327,9 +439,13 @@ describe('#createVerifier', () => {
327439 validBundles . v1 . dsse . withSigningCert
328440 ) ;
329441
330- it ( 'does not throw an error when invoked' , async ( ) => {
442+ it ( 'returns a Signer object when invoked' , async ( ) => {
331443 const verifier = await createVerifier ( tufOptions ! ) ;
332- expect ( verifier . verify ( bundle ) ) . toBeUndefined ( ) ;
444+ const result = verifier . verify ( bundle ) ;
445+ expect ( result ) . toBeDefined ( ) ;
446+ expect ( result ) . toHaveProperty ( 'key' ) ;
447+ expect ( result . key ) . toBeDefined ( ) ;
448+ expect ( result ) . toHaveProperty ( 'identity' ) ;
333449 } ) ;
334450 } ) ;
335451
@@ -345,4 +461,82 @@ describe('#createVerifier', () => {
345461 } ) . toThrowWithCode ( VerificationError , 'TLOG_BODY_ERROR' ) ;
346462 } ) ;
347463 } ) ;
464+
465+ describe ( '#createVerifier - BundleVerifier.verify Signer return tests' , ( ) => {
466+ describe ( 'when verifying valid bundles' , ( ) => {
467+ const bundle : SerializedBundle = fromPartial (
468+ validBundles . v1 . dsse . withSigningCert
469+ ) ;
470+
471+ it ( 'BundleVerifier.verify returns Signer with proper structure' , async ( ) => {
472+ const verifier = await createVerifier ( tufOptions ! ) ;
473+ const result = verifier . verify ( bundle ) ;
474+
475+ expect ( result ) . toMatchObject ( {
476+ key : expect . any ( Object ) ,
477+ identity : expect . any ( Object ) ,
478+ } ) ;
479+
480+ // Test the Signer type properties
481+ expect ( result . key ) . toHaveProperty ( 'asymmetricKeyType' ) ;
482+ } ) ;
483+
484+
485+ it ( 'BundleVerifier.verify throws error for invalid bundle but still returns Signer type when valid' , async ( ) => {
486+ const validVerifier = await createVerifier ( tufOptions ! ) ;
487+ const invalidBundle : SerializedBundle = fromPartial (
488+ invalidBundles . v1 . dsse . invalidBadSignature
489+ ) ;
490+
491+ // Test that invalid bundles still throw errors
492+ expect ( ( ) => {
493+ validVerifier . verify ( invalidBundle ) ;
494+ } ) . toThrowWithCode ( VerificationError , 'TLOG_BODY_ERROR' ) ;
495+
496+ // But valid bundles should return Signer
497+ const result = validVerifier . verify ( bundle ) ;
498+ expect ( result ) . toMatchObject ( {
499+ key : expect . any ( Object ) ,
500+ identity : expect . any ( Object ) ,
501+ } ) ;
502+ } ) ;
503+ } ) ;
504+
505+ describe ( 'when verifying with data payload' , ( ) => {
506+ const bundle : SerializedBundle = fromPartial (
507+ validBundles . v1 . messageSignature . withSigningCert
508+ ) ;
509+ const artifact = validBundles . artifact ;
510+
511+ it ( 'BundleVerifier.verify with data returns proper Signer' , async ( ) => {
512+ const verifier = await createVerifier ( tufOptions ! ) ;
513+ const result = verifier . verify ( bundle , artifact ) ;
514+
515+ expect ( result ) . toMatchObject ( {
516+ key : expect . any ( Object ) ,
517+ identity : expect . any ( Object ) ,
518+ } ) ;
519+
520+ // Verify identity contains expected certificate information
521+ expect ( result . identity ) . toBeDefined ( ) ;
522+ if ( result . identity ) {
523+ expect (
524+ result . identity . subjectAlternativeName || result . identity . extensions
525+ ) . toBeDefined ( ) ;
526+ }
527+ } ) ;
528+
529+ it ( 'BundleVerifier.verify returns Signer with working cryptographic key' , async ( ) => {
530+ const verifier = await createVerifier ( tufOptions ! ) ;
531+ const result = verifier . verify ( bundle , artifact ) ;
532+
533+ // Ensure the key can be exported and used
534+ expect ( ( ) => {
535+ const exported = result . key . export ( { format : 'pem' , type : 'spki' } ) ;
536+ expect ( typeof exported ) . toBe ( 'string' ) ;
537+ expect ( exported ) . toContain ( '-----BEGIN PUBLIC KEY-----' ) ;
538+ } ) . not . toThrow ( ) ;
539+ } ) ;
540+ } ) ;
541+ } ) ;
348542} ) ;
0 commit comments