@@ -11,23 +11,8 @@ function run() {
1111 const policyPath = fileURLToPath ( new URL ( './npm-audit-policy.json' , import . meta. url ) ) ;
1212 const policy = JSON . parse ( readFileSync ( policyPath , 'utf8' ) ) ;
1313 const npmCommand = process . platform === 'win32' ? 'npm.cmd' : 'npm' ;
14- const audit = spawnSync ( npmCommand , [ 'audit' , '--json' ] , {
15- encoding : 'utf8' ,
16- maxBuffer : 16 * 1024 * 1024 ,
17- timeout : 420_000 ,
18- } ) ;
19-
20- if ( audit . error ) {
21- console . error ( `Unable to run npm audit: ${ audit . error . message } ` ) ;
22- process . exit ( 1 ) ;
23- }
24-
25- let report ;
26- try {
27- report = JSON . parse ( audit . stdout ) ;
28- } catch {
29- console . error ( 'npm audit did not return valid JSON.' ) ;
30- if ( audit . stderr ) console . error ( audit . stderr . trim ( ) ) ;
14+ const report = runAudit ( npmCommand ) ;
15+ if ( ! report ) {
3116 process . exit ( 1 ) ;
3217 }
3318
@@ -51,6 +36,45 @@ function run() {
5136 }
5237}
5338
39+ export function runAudit (
40+ npmCommand ,
41+ execute = spawnSync ,
42+ warn = console . warn ,
43+ fail = console . error
44+ ) {
45+ const maxAttempts = 3 ;
46+ let lastFailure = 'unknown npm audit failure' ;
47+
48+ for ( let attempt = 1 ; attempt <= maxAttempts ; attempt += 1 ) {
49+ const audit = execute ( npmCommand , [ 'audit' , '--json' ] , {
50+ encoding : 'utf8' ,
51+ maxBuffer : 16 * 1024 * 1024 ,
52+ timeout : 180_000 ,
53+ } ) ;
54+
55+ if ( audit . error ) {
56+ lastFailure = audit . error . message ;
57+ } else {
58+ try {
59+ const report = JSON . parse ( audit . stdout ) ;
60+ if ( report ?. auditReportVersion === 2 && isRecord ( report . vulnerabilities ) ) {
61+ return report ;
62+ }
63+ lastFailure = `unexpected JSON response: ${ summarize ( report ) } ` ;
64+ } catch {
65+ lastFailure = audit . stderr . trim ( ) || 'npm audit did not return valid JSON' ;
66+ }
67+ }
68+
69+ if ( attempt < maxAttempts ) {
70+ warn ( `npm audit attempt ${ attempt } failed (${ lastFailure } ); retrying.` ) ;
71+ }
72+ }
73+
74+ fail ( `Unable to obtain a valid npm audit report after ${ maxAttempts } attempts: ${ lastFailure } ` ) ;
75+ return undefined ;
76+ }
77+
5478export function validateReport ( reportValue , policyValue , now ) {
5579 const validationErrors = [ ] ;
5680 if ( reportValue ?. auditReportVersion !== 2 || ! isRecord ( reportValue . vulnerabilities ) ) {
@@ -136,3 +160,8 @@ function sameStrings(actual, expected) {
136160function isRecord ( value ) {
137161 return typeof value === 'object' && value !== null && ! Array . isArray ( value ) ;
138162}
163+
164+ function summarize ( value ) {
165+ const summary = JSON . stringify ( value ) ?? String ( value ) ;
166+ return summary . length > 500 ? `${ summary . slice ( 0 , 500 ) } ...` : summary ;
167+ }
0 commit comments