@@ -24,7 +24,8 @@ class VerifySignatures {
2424 this . missing = [ ]
2525 this . checkedPackages = new Set ( )
2626 this . auditedWithKeysCount = 0
27- this . verifiedCount = 0
27+ this . verifiedSignatureCount = 0
28+ this . verifiedAttestationCount = 0
2829 this . exitCode = 0
2930 }
3031
@@ -78,12 +79,25 @@ class VerifySignatures {
7879 this . npm . output ( timing )
7980 this . npm . output ( '' )
8081
81- if ( this . verifiedCount ) {
82- const verifiedBold = this . npm . chalk . bold ( 'verified' )
83- if ( this . verifiedCount === 1 ) {
84- this . npm . output ( `${ this . verifiedCount } package has a ${ verifiedBold } registry signature` )
82+ const verifiedBold = this . npm . chalk . bold ( 'verified' )
83+ if ( this . verifiedSignatureCount ) {
84+ if ( this . verifiedSignatureCount === 1 ) {
85+ /* eslint-disable-next-line max-len */
86+ this . npm . output ( `${ this . verifiedSignatureCount } package has a ${ verifiedBold } registry signature` )
87+ } else {
88+ /* eslint-disable-next-line max-len */
89+ this . npm . output ( `${ this . verifiedSignatureCount } packages have ${ verifiedBold } registry signatures` )
90+ }
91+ this . npm . output ( '' )
92+ }
93+
94+ if ( this . verifiedAttestationCount ) {
95+ if ( this . verifiedAttestationCount === 1 ) {
96+ /* eslint-disable-next-line max-len */
97+ this . npm . output ( `${ this . verifiedAttestationCount } package has a ${ verifiedBold } attestation` )
8598 } else {
86- this . npm . output ( `${ this . verifiedCount } packages have ${ verifiedBold } registry signatures` )
99+ /* eslint-disable-next-line max-len */
100+ this . npm . output ( `${ this . verifiedAttestationCount } packages have ${ verifiedBold } attestations` )
87101 }
88102 this . npm . output ( '' )
89103 }
@@ -110,19 +124,35 @@ class VerifySignatures {
110124 const invalidClr = this . npm . chalk . bold ( this . npm . chalk . red ( 'invalid' ) )
111125 // We can have either invalid signatures or invalid provenance
112126 const invalidSignatures = this . invalid . filter ( i => i . code === 'EINTEGRITYSIGNATURE' )
113- if ( invalidSignatures . length === 1 ) {
114- this . npm . output ( `1 package has an ${ invalidClr } registry signature:` )
115- // } else if (invalidSignatures.length > 1) {
116- } else {
117- // TODO move this back to an else if once provenance attestation audit is added
118- /* eslint-disable-next-line max-len */
119- this . npm . output ( `${ invalidSignatures . length } packages have ${ invalidClr } registry signatures:` )
127+ if ( invalidSignatures . length ) {
128+ if ( invalidSignatures . length === 1 ) {
129+ this . npm . output ( `1 package has an ${ invalidClr } registry signature:` )
130+ } else {
131+ /* eslint-disable-next-line max-len */
132+ this . npm . output ( `${ invalidSignatures . length } packages have ${ invalidClr } registry signatures:` )
133+ }
134+ this . npm . output ( '' )
135+ invalidSignatures . map ( i =>
136+ this . npm . output ( `${ this . npm . chalk . red ( `${ i . name } @${ i . version } ` ) } (${ i . registry } )` )
137+ )
138+ this . npm . output ( '' )
120139 }
121- this . npm . output ( '' )
122- invalidSignatures . map ( i =>
123- this . npm . output ( `${ this . npm . chalk . red ( `${ i . name } @${ i . version } ` ) } (${ i . registry } )` )
124- )
125- this . npm . output ( '' )
140+
141+ const invalidAttestations = this . invalid . filter ( i => i . code === 'EATTESTATIONVERIFY' )
142+ if ( invalidAttestations . length ) {
143+ if ( invalidAttestations . length === 1 ) {
144+ this . npm . output ( `1 package has an ${ invalidClr } attestation:` )
145+ } else {
146+ /* eslint-disable-next-line max-len */
147+ this . npm . output ( `${ invalidAttestations . length } packages have ${ invalidClr } attestations:` )
148+ }
149+ this . npm . output ( '' )
150+ invalidAttestations . map ( i =>
151+ this . npm . output ( `${ this . npm . chalk . red ( `${ i . name } @${ i . version } ` ) } (${ i . registry } )` )
152+ )
153+ this . npm . output ( '' )
154+ }
155+
126156 if ( invalid . length === 1 ) {
127157 /* eslint-disable-next-line max-len */
128158 this . npm . output ( `Someone might have tampered with this package since it was published on the registry!` )
@@ -252,16 +282,19 @@ class VerifySignatures {
252282 const {
253283 _integrity : integrity ,
254284 _signatures,
285+ _attestations,
255286 _resolved : resolved ,
256287 } = await pacote . manifest ( `${ name } @${ version } ` , {
257288 verifySignatures : true ,
289+ verifyAttestations : true ,
258290 ...this . buildRegistryConfig ( registry ) ,
259291 ...this . npm . flatOptions ,
260292 } )
261293 const signatures = _signatures || [ ]
262294 const result = {
263295 integrity,
264296 signatures,
297+ attestations : _attestations ,
265298 resolved,
266299 }
267300 return result
@@ -287,14 +320,14 @@ class VerifySignatures {
287320 }
288321
289322 try {
290- const { integrity, signatures, resolved } = await this . verifySignatures (
323+ const { integrity, signatures, attestations , resolved } = await this . verifySignatures (
291324 name , version , registry
292325 )
293326
294327 // Currently we only care about missing signatures on registries that provide a public key
295328 // We could make this configurable in the future with a strict/paranoid mode
296329 if ( signatures . length ) {
297- this . verifiedCount += 1
330+ this . verifiedSignatureCount += 1
298331 } else if ( keys . length ) {
299332 this . missing . push ( {
300333 integrity,
@@ -305,17 +338,26 @@ class VerifySignatures {
305338 version,
306339 } )
307340 }
341+
342+ // Track verified attestations separately to registry signatures, as all
343+ // packages on registries with signing keys are expected to have registry
344+ // signatures, but not all packages have provenance and publish attestations.
345+ if ( attestations ) {
346+ this . verifiedAttestationCount += 1
347+ }
308348 } catch ( e ) {
309- if ( e . code === 'EINTEGRITYSIGNATURE' ) {
349+ if ( e . code === 'EINTEGRITYSIGNATURE' || e . code === 'EATTESTATIONVERIFY' ) {
310350 this . invalid . push ( {
311351 code : e . code ,
352+ message : e . message ,
312353 integrity : e . integrity ,
313354 keyid : e . keyid ,
314355 location,
315356 name,
316357 registry,
317358 resolved : e . resolved ,
318359 signature : e . signature ,
360+ predicateType : e . predicateType ,
319361 type,
320362 version,
321363 } )
0 commit comments