@@ -9,7 +9,7 @@ const DEMO_ROOT = join(__dirname, '..', '..');
99const REPORT_DIR = join ( DEMO_ROOT , 'csp-reports' ) ;
1010const SERVER_URL = process . env . CSP_SERVER_URL || 'http://localhost:8080' ;
1111const FRAMEWORK = ( process . env . CSP_FRAMEWORKS || 'jQuery' ) . trim ( ) ;
12- const CONCURRENCY = parseInt ( process . env . CSP_CONCURRENCY , 10 ) || 8 ;
12+ const CONCURRENCY = parseInt ( process . env . CSP_CONCURRENCY , 10 ) || 10 ;
1313
1414function findChrome ( ) {
1515 const candidates = [
@@ -84,10 +84,16 @@ function visitPage(url) {
8484 '--disable-software-rasterizer' ,
8585 '--disable-dev-shm-usage' ,
8686 '--dump-dom' ,
87- '--virtual-time-budget=5000 ' ,
87+ '--virtual-time-budget=2000 ' ,
8888 '--window-size=100,100' ,
8989 url ,
90- ] , { timeout : 30000 } , ( ) => resolve ( ) ) ;
90+ ] , { timeout : 50000 , killSignal : 'SIGKILL' } , ( error ) => {
91+ if ( error && error . killed ) {
92+ reject ( new Error ( `Chrome timed out for ${ url } ` ) ) ;
93+ } else {
94+ resolve ( ) ;
95+ }
96+ } ) ;
9197 child . on ( 'error' , ( err ) => {
9298 reject ( new Error ( `Failed to launch Chrome at "${ CHROME_PATH } ": ${ err . message } ` ) ) ;
9399 } ) ;
@@ -112,6 +118,22 @@ function httpRequest(url, method) {
112118 } ) ;
113119}
114120
121+ async function runPool ( items , concurrency , fn ) {
122+ let nextIndex = 0 ;
123+ async function worker ( ) {
124+ while ( nextIndex < items . length ) {
125+ const i = nextIndex ;
126+ nextIndex += 1 ;
127+ await fn ( items [ i ] , i ) ;
128+ }
129+ }
130+ const workers = [ ] ;
131+ for ( let w = 0 ; w < Math . min ( concurrency , items . length ) ; w += 1 ) {
132+ workers . push ( worker ( ) ) ;
133+ }
134+ await Promise . all ( workers ) ;
135+ }
136+
115137async function main ( ) {
116138 console . log ( `Chrome: ${ CHROME_PATH } ` ) ;
117139 console . log ( `Server: ${ SERVER_URL } ` ) ;
@@ -130,48 +152,40 @@ async function main() {
130152 let demosWithViolations = 0 ;
131153 const allViolations = [ ] ;
132154
133- for ( let batchStart = 0 ; batchStart < demos . length ; batchStart += CONCURRENCY ) {
134- const batch = demos . slice ( batchStart , batchStart + CONCURRENCY ) ;
155+ await httpRequest ( `${ SERVER_URL } /csp-violations` , 'DELETE' ) ;
135156
136- await httpRequest ( `${ SERVER_URL } /csp-violations` , 'DELETE' ) ;
157+ await runPool ( demos , CONCURRENCY , async ( demo , i ) => {
158+ const idx = i + 1 ;
159+ const snapshot = await httpRequest ( `${ SERVER_URL } /csp-violations` ) ;
160+ const since = snapshot . lastId || 0 ;
137161
138- await Promise . all ( batch . map ( ( demo ) => visitPage ( demo . url ) ) ) ;
139-
140- await new Promise ( ( resolve ) => { setTimeout ( resolve , 500 ) ; } ) ;
141-
142- const result = await httpRequest ( `${ SERVER_URL } /csp-violations` ) ;
143- const violations = result . violations || [ ] ;
144-
145- const violationsByUrl = { } ;
146- for ( const v of violations ) {
147- const uri = v . documentUri || '' ;
148- if ( ! violationsByUrl [ uri ] ) violationsByUrl [ uri ] = [ ] ;
149- violationsByUrl [ uri ] . push ( v ) ;
162+ try {
163+ await visitPage ( demo . url ) ;
164+ } catch ( err ) {
165+ console . log ( ` ⚠️ [${ idx } /${ demos . length } ] ${ demo . widget } /${ demo . demo } /${ demo . framework } — ${ err . message } ` ) ;
166+ return ;
150167 }
151168
152- for ( let j = 0 ; j < batch . length ; j += 1 ) {
153- const demo = batch [ j ] ;
154- const idx = batchStart + j + 1 ;
155- const demoViolations = violationsByUrl [ demo . url ]
156- || violationsByUrl [ `${ demo . url } index.html` ]
157- || [ ] ;
158-
159- if ( demoViolations . length > 0 ) {
160- demosWithViolations += 1 ;
161- totalViolations += demoViolations . length ;
162-
163- console . log ( ` ❌ [${ idx } /${ demos . length } ] ${ demo . widget } /${ demo . demo } /${ demo . framework } — ${ demoViolations . length } violation(s)` ) ;
164- for ( const v of demoViolations ) {
165- const blocked = v . blockedUri || 'N/A' ;
166- const directive = v . effectiveDirective || v . violatedDirective || '?' ;
167- console . log ( ` ${ directive } : ${ blocked } ` ) ;
168- allViolations . push ( { ...v , framework : FRAMEWORK } ) ;
169- }
170- } else {
171- console . log ( ` ✅ [${ idx } /${ demos . length } ] ${ demo . widget } /${ demo . demo } /${ demo . framework } ` ) ;
169+ const result = await httpRequest ( `${ SERVER_URL } /csp-violations?since=${ since } ` ) ;
170+ const violations = ( result . violations || [ ] ) . filter (
171+ ( v ) => v . documentUri === demo . url || v . documentUri === `${ demo . url } index.html` ,
172+ ) ;
173+
174+ if ( violations . length > 0 ) {
175+ demosWithViolations += 1 ;
176+ totalViolations += violations . length ;
177+
178+ console . log ( ` ❌ [${ idx } /${ demos . length } ] ${ demo . widget } /${ demo . demo } /${ demo . framework } — ${ violations . length } violation(s)` ) ;
179+ for ( const v of violations ) {
180+ const blocked = v . blockedUri || 'N/A' ;
181+ const directive = v . effectiveDirective || v . violatedDirective || '?' ;
182+ console . log ( ` ${ directive } : ${ blocked } ` ) ;
183+ allViolations . push ( { ...v , framework : FRAMEWORK } ) ;
172184 }
185+ } else {
186+ console . log ( ` ✅ [${ idx } /${ demos . length } ] ${ demo . widget } /${ demo . demo } /${ demo . framework } ` ) ;
173187 }
174- }
188+ } ) ;
175189
176190 const reportFile = join ( REPORT_DIR , `csp-violations-${ FRAMEWORK . toLowerCase ( ) } .jsonl` ) ;
177191
0 commit comments